R cuenta con varios paquetes de funciones que permiten trabajar con bases SQL con facilidad. A continuación vamos a ver algunas herramientas y ejemplos de como trabajar las bases de datos de la BdeC con R.

Paquetes

Hay dos paquetes útiles para trabajar bases SQL DBI y RODBC. Asimismo, dplyr cuenta con funciones que permiten exportar las consultas a formato SQL.

library(RODBC)
library(tidyverse)
library(dbplyr)

Conexión a la base y consultas

Me conecto a la base con la funcion odbcDriverConnect.

ch <- odbcDriverConnect(
  connection = "Driver=SQL Server; Server=BC-RETA;
                Database=Estimaciones_copia;
                UID=estimaciones_consulta;
                Pwd=Esti.bc.201923"
  )

Consulta SQL

sqlQuery permite utilizar el codigo de sql en R. La consulta se inserta como string.

En esta consulta seleccionamos se combinan 5 tablas y se selecciona para el cultivo trigo, en la campaña 18/19, en el nivel tecnologico alto, en la zona Retaa 5 las dosis de fertilizacion promedio.

consulta_Ruben <- sqlQuery(channel = ch, query = "--/////////////////////////////////////////////
--@id_consulta
--6 Fertilización
--7 Herbicidas
--8 Insecticidas
--3 Siembra
--10 Tratamiento de semilla
--9 Fungicidas
--/////////////////////////////////////////////
--@id_grano
--1 Trigo
--2 Cebada
--3 Girasol
--4 Sorgo
--5 Soja 1°
--6 Soja 2°
--7 Maíz 1° Temprano
--8 Maíz 1° Tardio y 2°
--/////////////////////////////////////////////
--@id_nivel
--1 Alto
--2 Medio
--3 Bajo
--/////////////////////////////////////////////
--@id_zona
--1     I   NOA
--2     IIe NEA Este (Chaco y Formosa)
--3     III Ctro N Cba
--4     IV  S Cba
--5     Vc  Ctro N SFe
--6     VI  Núcleo Norte
--7     VII Núcleo Sur
--8     VIII    Ctro E ER
--9     IX  N LP-OBA
--10    X   Ctro BA
--11    XI  SO BA-S LP
--12    XII SE BA
--13    XIII    San Luis
--14    XIV Cuenca Sal
--15    XV  Corrientes-Misiones
--16    IIo NEA Oeste (este de Sgo. del Estero)
--17    Vn  Norte SFe
--/////////////////////////////////////////////
--@id_campaña
--1  2010/2011
--2  2011/2012
--3  2012/2013
--4  2013/2014
--5  2014/2015
--6  2015/2016
--7  2016/2017
--8  2017/2018
--9  2018/2019
--10 2019/2020
declare @id_campaña int
declare @id_consulta int
declare @id_grano int
declare @id_nivel int
declare @id_zona int
set @id_campaña= 9 -- 2018/2019
set @id_consulta= 6--Fertilización
set @id_grano = 1 --Trigo
set @id_nivel= 1 -- nivel 1
set @id_zona = 5 -- Vc  Ctro N SFe 
SELECT (SELECT descripcion
                  FROM      Tipo_promedios
                  WHERE   (id = 1)) AS des_prom, 1 AS tipo_promedio, xx.id, xx.id_grano,
                          gg.descripcion AS des_grano, cc.id_tipo_pregunta, cc.id_caract, 
                            cc.descripcion AS des_caract, nn.descripcion AS des_nivel, xx.id_nivel,
                          xx.id_zona, zz.descripcion AS Expr1, zz.descripcion2, 
                            CAST(ISNULL((SELECT SUM(max) / COUNT(1) AS Expr1
                          FROM(SELECT ISNULL(t.max, 0) AS max
                          FROM Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
                          cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
                          WHERE   (t.max IS NOT NULL) AND (t.id_grano = xx.id_grano) AND
                          (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
                          (SELECT c.id_tipo_pregunta  FROM tipo_pregunta_retaa AS
                          p LEFT OUTER JOIN  Tipo_caracteristicas_retaa AS
                          c ON p.id = c.id_tipo_pregunta WHERE (p.id_filtro IN
                          (cc.id_tipo_pregunta)) AND (c.id_grano = xx.id_grano)
                                                                  GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.max_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
                                                                 ((SELECT COUNT(1) AS Expr1
                                                                   FROM      cabecera_transacciones_retaa
                                                                   WHERE   (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2), 0) AS DECIMAL(10, 2)) AS Alto_Promedio_max, 'http://bc-sellos/PruebaRetaa/pop_up_X_rubros.aspx?par=' + CAST(@id_campaña AS nvarchar(1)) 
                  + ';' + CAST(xx.id_grano AS nvarchar(2)) + ';' + CAST(xx.id_zona AS nvarchar(2)) + ';' + CAST(cc.id_tipo_pregunta AS nvarchar(2)) + ';' + CAST(cc.id_caract_2 AS nvarchar(3)) + ';' + CAST(xx.id_nivel AS nvarchar(3)) + ';' + '0' AS URL, 
                  CAST(ISNULL
                      ((SELECT SUM(min) / COUNT(1) AS Expr1
                        FROM      (SELECT ISNULL(t.min, 0) AS min
                                           FROM      Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
                                                             cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
                                           WHERE   (t.min IS NOT NULL) AND (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
                                                                 (SELECT c.id_tipo_pregunta
                                                                  FROM      tipo_pregunta_retaa AS p LEFT OUTER JOIN
                                                                                    Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
                                                                  WHERE   (p.id_filtro = cc.id_tipo_pregunta) AND (c.id_grano = xx.id_grano)
                                                                  GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.min_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
                                                                 ((SELECT COUNT(1) AS Expr1
                                                                   FROM      cabecera_transacciones_retaa AS cabecera_transacciones_retaa_7
                                                                   WHERE   (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1), 0) AS DECIMAL(10, 2)) AS Alto_Promedio_min, ISNULL
                      ((SELECT SUM(max_null) / COUNT(1) AS Expr1
                        FROM      (SELECT (CASE WHEN porc_aplic IS NULL THEN ISNULL(t .max, 0) ELSE ISNULL(t .max, 0) * porc_aplic / 100 END) AS max_null
                                           FROM      Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
                                                             cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
                                           WHERE   (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
                                                                 (SELECT c.id_tipo_pregunta
                                                                  FROM      tipo_pregunta_retaa AS p LEFT OUTER JOIN
                                                                                    Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
                                                                  WHERE   (p.id_filtro = cc.id_tipo_pregunta) AND (c.id_grano = xx.id_grano)
                                                                  GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.max_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
                                                                 ((SELECT COUNT(1) AS Expr1
                                                                   FROM      cabecera_transacciones_retaa AS cabecera_transacciones_retaa_6
                                                                   WHERE   (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS gg_1), 0) AS Alto_Promedio_max_null, ISNULL
                      ((SELECT SUM(max_null) / COUNT(1) AS Expr1
                        FROM      (SELECT (CASE WHEN porc_aplic IS NULL THEN ISNULL(t .min, 0) ELSE ISNULL(t .min, 0) * porc_aplic / 100 END) AS max_null
                                           FROM      Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
                                                             cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
                                           WHERE   (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta IN
                                                                 (SELECT c.id_tipo_pregunta
                                                                  FROM      tipo_pregunta_retaa AS p LEFT OUTER JOIN
                                                                                    Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
                                                                  WHERE   (p.id_filtro = cc.id_tipo_pregunta) AND (c.id_grano = xx.id_grano)
                                                                  GROUP BY c.id_tipo_pregunta)) AND (t.nivel = xx.id_nivel) AND (t.min_estado = 1) AND (t.id_caract = cc.id_caract_2) AND (t.estado_nivel = 1) AND (c.id_zona = xx.id_zona) AND
                                                                 ((SELECT COUNT(1) AS Expr1
                                                                   FROM      cabecera_transacciones_retaa AS cabecera_transacciones_retaa_5
                                                                   WHERE   (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS gg_1_1), 0) AS Alto_Promedio_min_null, cc.id_indice,
                      (SELECT descripcion
                       FROM      tipo_pregunta_retaa
                       WHERE   (id =
                                             (SELECT id_filtro
                                              FROM      tipo_pregunta_retaa AS tipo_pregunta_retaa_3
                                              WHERE   (id IN (cc.id_tipo_pregunta))))) AS des_consulta, CAST
                      (((SELECT SUM(max) / COUNT(1) AS Expr1
                         FROM      (SELECT ISNULL(t.max, 0) AS max
                                            FROM      Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
                                                              cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
                                            WHERE   (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta =
                                                                  (SELECT TOP (1) id_tipo_pregunta
                                                                   FROM      caract_id_grano AS caract_id_grano_2
                                                                   WHERE   (id_caract = gg.id_filtro_caract))) AND (t.nivel = 1) AND (t.id_caract = gg.id_filtro_caract) AND (t.max_estado = 1) AND (c.id_zona = xx.id_zona) AND
                                                                  ((SELECT COUNT(1) AS Expr1
                                                                    FROM      cabecera_transacciones_retaa AS cabecera_transacciones_retaa_2
                                                                    WHERE   (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_2) +
                      (SELECT SUM(min) / COUNT(1) AS Expr1
                       FROM      (SELECT ISNULL(t.min, 0) AS min
                                          FROM      Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
                                                            cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
                                          WHERE   (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta =
                                                                (SELECT TOP (1) id_tipo_pregunta
                                                                 FROM      caract_id_grano AS caract_id_grano_1
                                                                 WHERE   (id_caract = gg.id_filtro_caract))) AND (t.nivel = 1) AND (t.id_caract = gg.id_filtro_caract) AND (t.min_estado = 1) AND (c.id_zona = xx.id_zona) AND
                                                                ((SELECT COUNT(1) AS Expr1
                                                                  FROM      cabecera_transacciones_retaa AS cabecera_transacciones_retaa_1
                                                                  WHERE   (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_1_1)) / 2 / 100 *
                      (SELECT superficie
                       FROM      Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_1
                       WHERE   (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) AS DECIMAL(10, 0)) AS superficie_2, CAST
                      ((SELECT superficie
                        FROM      Superficie_retaa_x_campaña_grano
                        WHERE   (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) AS DECIMAL(10, 0)) AS superficie, zz.indice,
                      (SELECT SUM(max) / COUNT(1) AS Expr1
                       FROM      (SELECT ISNULL(t.max, 0) AS max
                                          FROM      Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
                                                            cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
                                          WHERE   (t.id_grano = xx.id_grano) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta = 2) AND (t.nivel = xx.id_nivel) AND (t.id_caract = 4) AND (t.max_estado = 1) AND (c.id_zona = xx.id_zona) AND
                                                                ((SELECT COUNT(1) AS Expr1
                                                                  FROM      cabecera_transacciones_retaa AS cabecera_transacciones_retaa_4
                                                                  WHERE   (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_1) AS Alto_Promedio_max_distribucion,
                      (SELECT SUM(max) / COUNT(1) AS Expr1
                       FROM      (SELECT ISNULL(t.max, 0) AS max
                                          FROM      Tipo_caracteristicas_retaa_trans AS t LEFT OUTER JOIN
                                                            cabecera_transacciones_retaa AS c ON c.id_trans = t.id_trans
                                          WHERE   (t.id_grano IN
                                                                (SELECT ID_MAPA
                                                                 FROM      Tipo_grano_reportes
                                                                 WHERE   (id = gg.id_grano_report))) AND (t.id_campaña = @id_campaña) AND (t.id_tipo_pregunta =
                                                                (SELECT TOP (1) id_tipo_pregunta
                                                                 FROM      caract_id_grano AS caract_id_grano_2
                                                                 WHERE   (id_caract = gg.id_filtro_caract))) AND (t.nivel = 1) AND (t.id_caract = gg.id_filtro_caract) AND (t.max_estado = 1) AND (c.id_zona = xx.id_zona) AND
                                                                ((SELECT COUNT(1) AS Expr1
                                                                  FROM      cabecera_transacciones_retaa AS cabecera_transacciones_retaa_2
                                                                  WHERE   (estado = 1) AND (id_trans = t.id_trans)) > 0)) AS a_2_1_2_1) *
                      (SELECT superficie
                       FROM      Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_1
                       WHERE   (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) / 100 AS superficie_3,
                      (SELECT primera
                       FROM      Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_2
                       WHERE   (id_grano =
                                             (SELECT id_grano_report
                                              FROM      Tipo_grano AS Tipo_grano_2
                                              WHERE   (id = xx.id_grano))) AND (id_campaña = @id_campaña) AND (id_zona = xx.id_zona)) *
                      (SELECT superficie
                       FROM      Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_3
                       WHERE   (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) / 100 AS Pas_primera_superficie,
                      (SELECT segunda
                       FROM      Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_1
                       WHERE   (id_grano =
                                             (SELECT id_grano_report
                                              FROM      Tipo_grano AS Tipo_grano_1
                                              WHERE   (id = xx.id_grano))) AND (id_campaña = @id_campaña) AND (id_zona = xx.id_zona)) *
                      (SELECT superficie
                       FROM      Superficie_retaa_x_campaña_grano AS Superficie_retaa_x_campaña_grano_4
                       WHERE   (id_grano = gg.id_grano_report) AND (id_zona = xx.id_zona) AND (id_campaña = @id_campaña)) / 100 AS pas_segunda_superficie, cc.tipo_unidad, CASE WHEN cc.id_tipo_pregunta = 7 OR
                  cc.id_tipo_pregunta = 6 THEN
                      (SELECT TOP (1) Coeficiente
                       FROM      Tipo_caracteristicas_retaa
                       WHERE   id_caract = cc.id_caract) ELSE '-1' END AS coeficiente, l.descripcion AS campaña
FROM     Granos_zonas_retaa AS xx LEFT OUTER JOIN
                  Tipo_zona_retaa AS zz ON xx.id_zona = zz.id_zona LEFT OUTER JOIN
                  Tipo_nivel AS nn ON xx.id_nivel = nn.id_nivel LEFT OUTER JOIN
                  Tipo_grano AS gg ON xx.id_grano = gg.id LEFT OUTER JOIN
                  Tipo_caracteristicas_retaa AS cc ON xx.id_grano = cc.id_grano AND cc.id_tipo_pregunta IN
                      (SELECT c.id_tipo_pregunta
                       FROM      tipo_pregunta_retaa AS p LEFT OUTER JOIN
                                         Tipo_caracteristicas_retaa AS c ON p.id = c.id_tipo_pregunta
                       WHERE   (p.id_filtro IN (@id_consulta)) AND (c.id_grano = xx.id_grano)
                       GROUP BY c.id_tipo_pregunta) LEFT OUTER JOIN
                  Año_campañas AS l ON cc.id_campaña = l.id
WHERE  (xx.id_grano IN (@id_grano)) AND (xx.id_zona IN (@id_zona)) AND (xx.id_nivel IN (@id_nivel)) AND (cc.id_caract_2 <> 104) AND (cc.id_caract_2 <> 105) AND (cc.id_caract_2 <> 106) AND (cc.id_caract_2 <> 107) AND (cc.id_caract_2 <> 108) AND 
                  (cc.id_caract_2 <> 65) AND (cc.id_campaña = @id_campaña);")
consulta_Ruben

Paquete DBI

DBI permite conectarno a la base de datos de SQL. Para hacerlo debemos configurar los campos. La conexión se puede verificar en el panel superior derecho.

La base datos del ReTAA esta compuesta por 6 tablas principales “Año Campañas”, “cabecera_trnsacciones_retaa”, “caract_id_grano”, “caract_id_grano_campaña_vista”, “Colaboradores” y “Granos_zonas_retaa”.

#Me conecto a la base
con <- DBI::dbConnect(odbc::odbc(),
                      Driver    = "SQL Server", 
                      Server    = "BC-RETA",
                      Database  = "Estimaciones_copia",
                      UID       = "estimaciones_consulta",
                      PWD       = "Esti.bc.201923",
                      Port      = 1433,
                      dbname = "Estimaciones_Copia",
                      encoding = "latin1")
DBI::dbListTables(con)[1:6]#lista de las tablas de la base
[1] "Año_campañas"                 "cabecera_transacciones_retaa"  
[3] "caract_id_grano"                "caract_id_grano_campaña_vista"
[5] "Colaboradores"                  "Granos_zonas_retaa"            

la función tbl de dplyr trae las tablas de la base de datos. Tambien podemos aplicar a esta tabla todas las funciones que vimos en las clases previas.

Veamos algunas de las tablas que conforman la base del ReTAA.

Tabla Tipo_grano

#Tabla id grano
Tipo_grano <-  tbl(con, c("Tipo_grano")) %>% 
  select(id,descripcion) %>% rename(id_grano = id, descripcion_grano = descripcion) %>% filter(id_grano>0)
Tipo_grano 

Tabla Año_campañas

#selecciono tabla id campaña
Anio_campanias <-  tbl(con, c("Año_campañas")) %>% rename(id_campania = id, descripcion_campania = descripcion) %>% filter(id_campania>0)
Anio_campanias 

Tabla Tipo_zona_retaa

#cabecera_transacciones_retaa
Tipo_zona_retaa <- tbl(con, c("Tipo_zona_retaa")) %>% select(id_zona,descripcion,descripcion2) %>% rename(descripcion_zona_retaa = descripcion,
       descripcion_zona_retaa2 = descripcion2)
Tipo_zona_retaa  %>% head(10)

Tabla cabecera_transacciones_retaa

#cabecera_transacciones_retaa
cabecera_transacciones_retaa <- tbl(con, c("cabecera_transacciones_retaa")) %>% select(id_trans,id_colaborador,estado)
cabecera_transacciones_retaa  %>% head(10)

Tabla tipo_pregunta_retaa

#cabecera_transacciones_retaa
tipo_pregunta_retaa <- tbl(con, c("tipo_pregunta_retaa")) %>% 
  select(id,descripcion) %>% rename(id_pregunta = id, descripcion_pregunta = descripcion) %>% as_tibble()
tipo_pregunta_retaa

Tabla tipo_caracteristica_retaa

#cabecera_transacciones_retaa
Tipo_caracteristicas_retaa <- tbl(con, c("Tipo_caracteristicas_retaa_trans"))
Tipo_caracteristicas_retaa

Tabla Colaboradores

#Tabla Colaboradores
Colaboradores <- tbl(con, c("Colaboradores"))
Colaboradores %>% variable.names()
 [1] "id_colaborador"  "id_Zona"         "id_semana"       "fec_alta"        "Empresa"        
 [6] "Nombre"          "Apellido"        "Localidad"       "Provincia"       "Telefono"       
[11] "Celular"         "e_mail"          "obs"             "poligono"        "id_usuario"     
[16] "fec_ultimaMod"   "id_usuarioMod"   "Emp_vinculada"   "estado"          "direccion"      
[21] "cp"              "dto"             "localidad1"      "tipo_nivel"      "id_zona_retaa"  
[26] "id_estado_retaa" "obs_retaa"       "latitud"         "logitud"        

Tambien podemos visualizar las conexxiones entre las tablas con el paquete datamodelr que nos permite construir diagramas entidad-realación

library(datamodelr) #paquete para armar diagrama de entidad relacion
coneccion <- odbcDriverConnect(
  connection = "Driver=SQL Server; Server=BC-RETA; Database=Estimaciones_copia; UID=estimaciones_consulta; Pwd=Esti.bc.201923"
  )
sQuery <- dm_re_query("sqlserver")
dm_retaa <- sqlQuery(channel = coneccion, sQuery, stringsAsFactors = FALSE, errors=TRUE)
dm_retaa <- as.data_model(dm_retaa) #paso a formato modelo
focus <-list(tables  = c("Año_campañas","cabecera_transacciones_retaa","caract_id_grano",               
"caract_id_grano_campaña_vista","Colaboradores","Granos_zonas_retaa")) 
 
graph <- dm_create_graph(dm_retaa , rankdir = "BT", focus = focus, col_attr = c("column", "type")) 
dm_render_graph(graph) #grafico
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio

Query SQL vs dplyr

En esta seccion vamos a replicar la consulta SQL que vimos arriba pero en fomrato dplyr. Vamos a ver que una consulta muy extensa se puede realizar en una fomra más prolija y breve.

El comandoshow_query permite extraer la consulta en formato SQL.

tabla_consulta_sql <- Tipo_caracteristicas_retaa %>%  
  left_join(cabecera_transacciones_retaa,by = c("id_trans","id_colaborador")) %>% #join con tabla cabecera
  left_join(Tipo_grano ,by = "id_grano") %>%
  left_join(Anio_campanias ,by = c("id_campaña"="id_campania") ) %>%
  left_join(Tipo_zona_retaa, by = c("id_zona")  ) %>% 
  filter(id_campaña == 9,id_zona==5,nivel==1,id_grano==1,
         id_tipo_pregunta==6, max_estado == 1, estado==1) %>%
  group_by(descripcion_grano, id_grano, descripcion_campania, id_campaña, descripcion_zona_retaa, id_zona,
          nivel, id_tipo_pregunta, id_caract,descripcion) %>% 
  summarise(promedio_max = round(mean(max, na.rm = T),2),
            promedio_min = round(mean(min, na.rm = T),2)) 
tabla_consulta_sql %>% dplyr::show_query() #ver query SQL
<SQL>
SELECT "descripcion_grano", "id_grano", "descripcion_campania", "id_campaña", "descripcion_zona_retaa", "id_zona", "nivel", "id_tipo_pregunta", "id_caract", "descripcion", ROUND(AVG("max"), 2) AS "promedio_max", ROUND(AVG("min"), 2) AS "promedio_min"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "LHS"."estado" AS "estado", "LHS"."descripcion_grano" AS "descripcion_grano", "LHS"."descripcion_campania" AS "descripcion_campania", "RHS"."descripcion_zona_retaa" AS "descripcion_zona_retaa", "RHS"."descripcion_zona_retaa2" AS "descripcion_zona_retaa2"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "LHS"."estado" AS "estado", "LHS"."descripcion_grano" AS "descripcion_grano", "RHS"."descripcion_campania" AS "descripcion_campania"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "LHS"."estado" AS "estado", "RHS"."descripcion_grano" AS "descripcion_grano"
FROM (SELECT "LHS"."id_trans" AS "id_trans", "LHS"."id_campaña" AS "id_campaña", "LHS"."id_colaborador" AS "id_colaborador", "LHS"."id_grano" AS "id_grano", "LHS"."id_tipo_pregunta" AS "id_tipo_pregunta", "LHS"."id_caract" AS "id_caract", "LHS"."descripcion" AS "descripcion", "LHS"."tipo_unidad" AS "tipo_unidad", "LHS"."max" AS "max", "LHS"."min" AS "min", "LHS"."obs" AS "obs", "LHS"."nivel" AS "nivel", "LHS"."max_estado" AS "max_estado", "LHS"."min_estado" AS "min_estado", "LHS"."id_indice" AS "id_indice", "LHS"."estado_nivel" AS "estado_nivel", "LHS"."porc_aplic" AS "porc_aplic", "LHS"."por_1" AS "por_1", "LHS"."por_2" AS "por_2", "LHS"."id_zona" AS "id_zona", "LHS"."id" AS "id", "RHS"."estado" AS "estado"
FROM "Tipo_caracteristicas_retaa_trans" AS "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT "id_trans", "id_colaborador", "estado"
FROM "cabecera_transacciones_retaa") "RHS"
ON ("LHS"."id_trans" = "RHS"."id_trans" AND "LHS"."id_colaborador" = "RHS"."id_colaborador")
) "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT *
FROM (SELECT TOP 100 PERCENT "id" AS "id_grano", "descripcion" AS "descripcion_grano"
FROM "Tipo_grano") "dbplyr_003"
WHERE ("id_grano" > 0.0)) "RHS"
ON ("LHS"."id_grano" = "RHS"."id_grano")
) "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT *
FROM (SELECT TOP 100 PERCENT "id" AS "id_campania", "descripcion" AS "descripcion_campania"
FROM "Año_campañas") "dbplyr_004"
WHERE ("id_campania" > 0.0)) "RHS"
ON ("LHS"."id_campaña" = "RHS"."id_campania")
) "LHS"
LEFT JOIN (SELECT TOP 100 PERCENT "id_zona", "descripcion" AS "descripcion_zona_retaa", "descripcion2" AS "descripcion_zona_retaa2"
FROM "Tipo_zona_retaa") "RHS"
ON ("LHS"."id_zona" = "RHS"."id_zona")
) "dbplyr_005"
WHERE (("id_campaña" = 9.0) AND ("id_zona" = 5.0) AND ("nivel" = 1.0) AND ("id_grano" = 1.0) AND ("id_tipo_pregunta" = 6.0) AND ("max_estado" = 1.0) AND ("estado" = 1.0))
GROUP BY "descripcion_grano", "id_grano", "descripcion_campania", "id_campaña", "descripcion_zona_retaa", "id_zona", "nivel", "id_tipo_pregunta", "id_caract", "descripcion"
tabla_consulta_sql #salida

Planteos Tecnologicos

Construir los planteos tecnológicos suele ser un trabajo que tedioso que no esta automatizado y suele tomar bastante tiempo. En esta sección buscamos automatizar la construcción de los planteos.

# tabla con todas los insumos incluidos en la base
tabla_variables <- Tipo_caracteristicas_retaa %>% distinct(descripcion,tipo_unidad) %>% as_tibble()
#lista de variables incluidas
variables_planteo <- c("Adopción de NT","max_min","nivel","id_campaña","id_grano","id_zona",
                       "descr_grano","descr_campania","Semilla","Urea","PDA",
                       "Glifosato concentrado - Barbecho",
                       "Glifosato concentrado - cultivo","Hib. RR Bt2","2-4D","Dicamba",
                       "Metsulfurón",
                       "SPS","Atrazina","Metolaclor","Piclorám","Diamidas","Diclosulam", 
                       "Fungicida 1 (Estrob. + Triazol)","Semilla", "Inoc. + Fungic.",
                       "Inoculante 1 (full)","Fosforados 1", "Fosforados 2",
                       "Curasemilla - Fungicida base","Clorimurón",
                       "PMA","Dimetoato", "Curasemilla 2 - Fungicida",
"Curasemilla 2 - fungic."," 
Fungicida 2")
#Armo la consulta de planteos
planteos <- Tipo_caracteristicas_retaa %>%  
  filter(descripcion %in% variables_planteo) %>% #me quedo con insumos incluidos en los planteos
  left_join(cabecera_transacciones_retaa, by = c("id_trans","id_colaborador")) %>% 
  left_join(Tipo_zona_retaa, by=c("id_zona")) %>% 
  left_join(Tipo_grano, by="id_grano") %>%
  #left_join(tipo_pregunta_retaa, by = c("id_tipo_pregunta"= "id_pregunta")) %>% 
  left_join(Anio_campanias,by=c("id_campaña"="id_campania" )) %>%
  filter(estado==1) %>% #encuestas validadas
  #correcion maiz tardio por carga retaa
  mutate(id_grano = case_when( (id_grano==8 & id_zona %in% c(1,2,16) )~ 7,
                                                     T ~ as.double(id_grano) ),
         descripcion_grano = ifelse(id_grano==7, "Maíz 1° Temprano",descripcion_grano)
         ) %>% 
  mutate(max = case_when(tipo_unidad =="%" & is.na(max) ~ 0,
                         T ~ as.numeric(max) ),
         min = case_when(tipo_unidad =="%" & is.na(min) ~ as.numeric(max),
         T ~ as.numeric(min)
                         )
         ) %>% 
   group_by( id_campaña ,descripcion_campania , nivel, 
             id_zona, descripcion_zona_retaa,
             id_grano, descripcion_grano, descripcion) %>% 
  summarise(promedio_max = mean(max, na.rm = T), #promedio maximo aplicado
            promedio_min = mean(min, na.rm = T) #promedio minimo aplicado
            #promedio_porc_aplic = mean(porc_aplic, na.rm = T)
            ) %>% 
  mutate(doble_na = ifelse( is.na(promedio_max) & is.na(promedio_min),1,0 )) %>%
  filter(doble_na !=1) %>% 
  mutate( promedio = (promedio_max+ promedio_min)/2) %>% 
  select(-c(promedio_max,promedio_min) ) 
  
#Funcion para escalar el nivel de adopcion tecnologica
#escalar <- function(x){ x = x/sum(x,na.rm = T) *100 }
#Genero descripcion Nivel Tecnológico y escalo Adopcion de NT
planteos <- planteos %>% as_tibble() %>% 
  mutate(descripcion_nivel = case_when(nivel == 1 ~ "Alto",
                                       nivel == 2 ~ "Medio",
                                       nivel == 3 ~ "Bajo")) %>% 
  pivot_wider(names_from = descripcion,values_from = c(promedio) ) %>% 
  group_by(id_campaña,id_zona,id_grano)# %>%
  #mutate(Adopcion_NT = escalar(`Adopción de NT`))   #escalo a 100 el nivel tecnologico
#Paso a formato long
planteos <- planteos %>%
  mutate(adopcion_nt = `Adopción de NT`) %>% 
  pivot_longer(cols = -c("id_campaña", "descripcion_campania","nivel","id_zona","descripcion_zona_retaa" ,"id_grano","descripcion_grano", "descripcion_nivel","adopcion_nt") ,names_to = "variables",values_to = "valores")
Tipo_zona_retaa
planteos_pond <- planteos %>%
  group_by(id_campaña,descripcion_campania,id_zona, descripcion_zona_retaa,
           id_grano,descripcion_grano,variables) %>%
  filter(!is.na(valores) ) %>% #esto es para no contar los no contestados y calcular los planteos Retaa "promedio simple"
  summarise(valores =  weighted.mean(valores ,w = adopcion_nt/100,na.rm = T)
            )

Planteos

Soja
variables_planteo_soja <-c("Semilla", "SPS","Glifosato concentrado - Barbecho",
                           "Glifosato concentrado - cultivo", "2-4D","Clorimurón",
                           "Metsulfurón","Diclosulam","Diamidas",
                           "Estrobirulina + Triazol","Inoculante 1 (full)","Inoc. + Fungic.","Fungicida 2") 
planteo_soja <- planteos_pond  %>% 
  filter(descripcion_grano=="Soja 1°",variables %in% variables_planteo_soja) %>% ungroup()
  
  
planteos_pond  %>% 
  filter(descripcion_grano=="Soja 1°",variables %in% variables_planteo_soja) %>% 
  ggplot(.,mapping = aes(y=valores,x=descripcion_campania, color=as.factor(descripcion_zona_retaa)))+ 
  geom_point() +  facet_wrap(~variables, scales = "free_y")+
  labs(title =  "Dosis aplicadas - Soja 1º")+
  labs(x="Campaña", color="Zona")+
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "bottom"
        ) 

planteos  %>% 
  filter(descripcion_grano=="Soja 1°",variables %in% variables_planteo_soja) %>% 
  filter(descripcion_campania=="2017/2018",descripcion_zona_retaa=="III")
planteos %>% filter(variables=="Adopción de NT") %>% group_by(id_grano, descripcion_grano, descripcion_zona_retaa,descripcion_campania) %>%  summarise(adopcion = sum(valores))
planteos %>% filter(descripcion_campania=="2016/2017", descripcion_zona_retaa=="III",
                    id_grano==2, variables=="Adopción de NT")
Trigo
variables_planteo_Trigo <-c("Semilla","Urea","PMA","Glifosato concentrado - Barbecho",
                           "2-4D","Dicamba", "Metsulfurón","Fosforados 1","Fungicida 1 (Estrob. + Triazol)",
                           "Curasemilla 2 - Fungicida","Curasemilla 2 - fungic.") #Lambdacialotrina no lo encontré
planteo_trigo <- planteos_pond  %>% 
  filter(descripcion_grano=="Trigo",variables %in% variables_planteo_Trigo) %>% ungroup()
  
planteos_pond  %>% 
  filter(descripcion_grano=="Trigo",variables %in% variables_planteo_Trigo) %>% 
  ggplot(.,mapping = aes(y=valores,x=descripcion_campania, color=as.factor(descripcion_zona_retaa)))+ 
  geom_point() +  facet_wrap(~variables, scales = "free_y")+
  labs(title =  "Dosis aplicadas - Trigo")+
  labs(x="Campaña", color="Zona")+
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "bottom"
        ) 

Maiz
variables_planteo_Maiz <-c( "Hib. RR Bt2", "Urea","PDA","Glifosato concentrado - Barbecho",
                           "Glifosato concentrado - cultivo", "2-4D","Atrazina",
                           "Metolaclor","Piclorám","Diamidas",
                           "Dicamba", "Estrobirulina + Triazol") #Lambdacialotrina no lo encontré
planteo_maiz <- planteos_pond  %>% 
  filter(descripcion_grano=="Maíz 1° Temprano",variables %in% variables_planteo_Maiz) %>% ungroup() 
planteos_pond  %>% 
  filter(descripcion_grano=="Maíz 1° Temprano",variables %in% variables_planteo_Maiz) %>% 
  ggplot(.,mapping = aes(y=valores,x=descripcion_campania, color=as.factor(descripcion_zona_retaa)))+ 
  geom_point() +  facet_wrap(~variables, scales = "free_y")+
  labs(title =  "Dosis aplicadas - Maiz")+
  labs(x="Campaña", color="Zona")+
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "bottom"
        ) 

Guardo planteos

library(openxlsx) #activamos la librería
write.xlsx(x = planteos_pond, file = "datasets/planteos.xlsx", row.names = FALSE)

Evolución del nivel tecnológico

Maiz 1º
planteos %>% filter(descripcion_grano=="Maíz 1° Temprano", variables=="Adopción de NT") %>% 
ggplot(.,mapping = aes(x = descripcion_campania, y = valores, group=nivel,fill = as.factor(descripcion_nivel))) +
  geom_col() +
  facet_wrap(~descripcion_zona_retaa)+  theme_bw()+
  labs(title =  "Nivel tecnológico por zona - Maíz temprano")+
  labs(x="Campaña", fill="Nivel tecnológico")+
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "top"
        ) 

Maiz Tardio y 2º

Soja
planteos %>% filter(descripcion_grano=="Soja 1°", variables=="Adopción de NT") %>% 
ggplot(.,mapping = aes(x = descripcion_campania, y = valores, group=nivel,fill = as.factor(descripcion_nivel))) +
  geom_col() +
  facet_wrap(~descripcion_zona_retaa)+  theme_bw()+
  labs(title =  "Nivel tecnológico por zona -Soja")+
  labs(x="Campaña", fill="Nivel tecnológico")+
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "top"
        ) 

Trigo
planteos %>% filter(descripcion_grano=="Trigo" , variables=="Adopción de NT") %>% 
ggplot(.,mapping = aes(x = descripcion_campania, y = valores, group=nivel,fill = as.factor(descripcion_nivel))) +
  geom_col() +
  facet_wrap(~descripcion_zona_retaa)+  theme_bw()+
  labs(title =  "Nivel tecnológico por zona -Trigo")+
  labs(x="Campaña", fill="Nivel tecnológico")+
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "top"
        ) 

Girasol

Cebada

Dosis de fertilización

#Grafico
planteos %>% filter(descripcion_grano=="Maíz 1° Temprano", variables=="Urea")  %>%  #filtro cultivo
ggplot(.,mapping = aes(x = descripcion_campania,
                       y = valores, group=nivel,color = as.factor(descripcion_nivel))) +
  geom_line() + geom_point()+
  facet_wrap(~descripcion_zona_retaa) +  
  theme_bw() +
  labs(title =  "Fertilización con Urea (kg/ha) en Maíz temprano")+
  labs(x="Campaña", color="Nivel tecnológico")+
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "bottom"
        )

#Grafico
planteos_pond %>% filter(descripcion_grano=="Maíz 1° Temprano", variables=="Urea")  %>%  #filtro cultivo
ggplot(.,mapping = aes(x = descripcion_campania,
                       y = valores, group=1)) +
  geom_line() + geom_point()+
  facet_wrap(~descripcion_zona_retaa) +  
  theme_bw() +
  labs(title =  "Fertilización con Urea (kg/ha) en Maíz temprano")+
  labs(x="Campaña", color="Nivel tecnológico")+
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "bottom"
        )

#Grafico
planteos_pond %>% filter(descripcion_grano=="Trigo", variables=="Urea")  %>%  #filtro cultivo
ggplot(.,mapping = aes(x = descripcion_campania,
                       y = valores, group=1)) +
  geom_line() + geom_point()+
  facet_wrap(~descripcion_zona_retaa) +  
  theme_bw() +
  labs(title =  "Fertilización con Urea (kg/ha) en Trigo")+
  labs(x="Campaña", color="Nivel tecnológico")+
  theme(axis.text.x = element_text(angle = 90),
        legend.position = "bottom"
        )

Precios

https://emoriebeck.github.io/R-tutorials/purrr/#

unique(planteos$variables)
 [1] "doble_na"                         "2-4D"                            
 [3] "PDA"                              "Semilla"                         
 [5] "Fosforados 2"                     "Atrazina"                        
 [7] "Hib. RR Bt2"                      "Dicamba"                         
 [9] "Fosforados 1"                     "Adopción de NT"                  
[11] "Curasemilla 2 - Fungicida"        "Inoculante 1 (full)"             
[13] "Metsulfurón"                      "SPS"                             
[15] "Clorimurón"                       "Urea"                            
[17] "PMA"                              "Fungicida 1 (Estrob. + Triazol)" 
[19] "Inoc. + Fungic."                  "Diamidas"                        
[21] "Diclosulam"                       "Metolaclor"                      
[23] "Curasemilla 2 - fungic."          "Piclorám"                        
[25] "Glifosato concentrado - Barbecho" "Glifosato concentrado - cultivo" 
[27] "Curasemilla - Fungicida base"    
LS0tDQp0aXRsZTogQmFzZXMgU1FMIGVuIFINCnN1YnRpdGxlOiBJbnRyb2R1Y2Npw7NuDQpkYXRlOiAiIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KLS0tDQoNClIgY3VlbnRhIGNvbiB2YXJpb3MgcGFxdWV0ZXMgZGUgZnVuY2lvbmVzIHF1ZSBwZXJtaXRlbiB0cmFiYWphciBjb24gYmFzZXMgU1FMIGNvbiBmYWNpbGlkYWQuIEEgY29udGludWFjacOzbiB2YW1vcyBhIHZlciBhbGd1bmFzIGhlcnJhbWllbnRhcyB5IGVqZW1wbG9zIGRlIGNvbW8gdHJhYmFqYXIgbGFzIGJhc2VzIGRlIGRhdG9zIGRlIGxhIEJkZUMgY29uIFIuDQoNCg0KIyMjIFBhcXVldGVzDQoNCkhheSBkb3MgcGFxdWV0ZXMgw7p0aWxlcyBwYXJhIHRyYWJhamFyIGJhc2VzIFNRTCBgREJJYCB5IGBST0RCQ2AuIEFzaW1pc21vLCBgZHBseXJgIGN1ZW50YSBjb24gZnVuY2lvbmVzIHF1ZSBwZXJtaXRlbiBleHBvcnRhciBsYXMgY29uc3VsdGFzIGEgZm9ybWF0byBTUUwuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KFJPREJDKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRicGx5cikNCmBgYA0KDQojIyMgQ29uZXhpw7NuIGEgbGEgYmFzZSB5IGNvbnN1bHRhcw0KDQpNZSBjb25lY3RvIGEgbGEgYmFzZSBjb24gbGEgZnVuY2lvbiBvZGJjRHJpdmVyQ29ubmVjdC4NCg0KYGBge3J9DQpjaCA8LSBvZGJjRHJpdmVyQ29ubmVjdCgNCiAgY29ubmVjdGlvbiA9ICJEcml2ZXI9U1FMIFNlcnZlcjsgU2VydmVyPUJDLVJFVEE7DQogICAgICAgICAgICAgICAgRGF0YWJhc2U9RXN0aW1hY2lvbmVzX2NvcGlhOw0KICAgICAgICAgICAgICAgIFVJRD1lc3RpbWFjaW9uZXNfY29uc3VsdGE7DQogICAgICAgICAgICAgICAgUHdkPUVzdGkuYmMuMjAxOTIzIg0KICApDQoNCmBgYA0KDQoNCiMjIyBDb25zdWx0YSBTUUwNCg0Kc3FsUXVlcnkgcGVybWl0ZSB1dGlsaXphciBlbCBjb2RpZ28gZGUgc3FsIGVuIFIuIExhIGNvbnN1bHRhIHNlIGluc2VydGEgY29tbyBzdHJpbmcuDQoNCkVuIGVzdGEgY29uc3VsdGEgc2VsZWNjaW9uYW1vcyBzZSBjb21iaW5hbiA1IHRhYmxhcyB5IHNlIHNlbGVjY2lvbmEgcGFyYSBlbCBjdWx0aXZvIHRyaWdvLCBlbiBsYSBjYW1wYcOxYSAxOC8xOSwgIGVuIGVsIG5pdmVsIHRlY25vbG9naWNvIGFsdG8sIGVuIGxhIHpvbmEgUmV0YWEgNSBsYXMgZG9zaXMgZGUgZmVydGlsaXphY2lvbiBwcm9tZWRpby4NCg0KYGBge3IsIGVjaG89VH0NCmNvbnN1bHRhX1J1YmVuIDwtIHNxbFF1ZXJ5KGNoYW5uZWwgPSBjaCwgcXVlcnkgPSAiLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX2NvbnN1bHRhDQotLTYJRmVydGlsaXphY2nDs24NCi0tNwlIZXJiaWNpZGFzDQotLTgJSW5zZWN0aWNpZGFzDQotLTMJU2llbWJyYQ0KLS0xMCBUcmF0YW1pZW50byBkZSBzZW1pbGxhDQotLTkJRnVuZ2ljaWRhcw0KLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX2dyYW5vDQotLTEJVHJpZ28NCi0tMglDZWJhZGENCi0tMwlHaXJhc29sDQotLTQJU29yZ28NCi0tNQlTb2phIDHCsA0KLS02CVNvamEgMsKwDQotLTcJTWHDrXogMcKwIFRlbXByYW5vDQotLTgJTWHDrXogMcKwIFRhcmRpbyB5IDLCsA0KLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX25pdmVsDQotLTEJQWx0bw0KLS0yCU1lZGlvDQotLTMJQmFqbw0KLS0vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8NCi0tQGlkX3pvbmENCi0tMQkgICAgSQlOT0ENCi0tMgkgICAgSUllCU5FQSBFc3RlIChDaGFjbyB5IEZvcm1vc2EpDQotLTMJICAgIElJSQlDdHJvIE4gQ2JhDQotLTQJICAgIElWCVMgQ2JhDQotLTUJICAgIFZjCUN0cm8gTiBTRmUNCi0tNgkgICAgVkkJTsO6Y2xlbyBOb3J0ZQ0KLS03CSAgICBWSUkJTsO6Y2xlbyBTdXINCi0tOAkgICAgVklJSQlDdHJvIEUgRVINCi0tOQkgICAgSVgJTiBMUC1PQkENCi0tMTAJWAlDdHJvIEJBDQotLTExCVhJCVNPIEJBLVMgTFANCi0tMTIJWElJCVNFIEJBDQotLTEzCVhJSUkJU2FuIEx1aXMNCi0tMTQJWElWCUN1ZW5jYSBTYWwNCi0tMTUJWFYJQ29ycmllbnRlcy1NaXNpb25lcw0KLS0xNglJSW8JTkVBIE9lc3RlIChlc3RlIGRlIFNnby4gZGVsIEVzdGVybykNCi0tMTcJVm4JTm9ydGUgU0ZlDQotLS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLw0KLS1AaWRfY2FtcGHDsWENCi0tMQkgMjAxMC8yMDExDQotLTIJIDIwMTEvMjAxMg0KLS0zCSAyMDEyLzIwMTMNCi0tNAkgMjAxMy8yMDE0DQotLTUJIDIwMTQvMjAxNQ0KLS02CSAyMDE1LzIwMTYNCi0tNwkgMjAxNi8yMDE3DQotLTgJIDIwMTcvMjAxOA0KLS05CSAyMDE4LzIwMTkNCi0tMTAgMjAxOS8yMDIwDQoNCmRlY2xhcmUgQGlkX2NhbXBhw7FhIGludA0KZGVjbGFyZSBAaWRfY29uc3VsdGEgaW50DQpkZWNsYXJlIEBpZF9ncmFubyBpbnQNCmRlY2xhcmUgQGlkX25pdmVsIGludA0KZGVjbGFyZSBAaWRfem9uYSBpbnQNCg0Kc2V0IEBpZF9jYW1wYcOxYT0gOSAtLSAyMDE4LzIwMTkNCnNldCBAaWRfY29uc3VsdGE9IDYtLUZlcnRpbGl6YWNpw7NuDQpzZXQgQGlkX2dyYW5vID0gMSAtLVRyaWdvDQpzZXQgQGlkX25pdmVsPSAxIC0tIG5pdmVsIDENCnNldCBAaWRfem9uYSA9IDUgLS0gVmMJQ3RybyBOIFNGZSANCg0KU0VMRUNUIChTRUxFQ1QgZGVzY3JpcGNpb24NCiAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX3Byb21lZGlvcw0KICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWQgPSAxKSkgQVMgZGVzX3Byb20sIDEgQVMgdGlwb19wcm9tZWRpbywgeHguaWQsIHh4LmlkX2dyYW5vLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZy5kZXNjcmlwY2lvbiBBUyBkZXNfZ3Jhbm8sIGNjLmlkX3RpcG9fcHJlZ3VudGEsIGNjLmlkX2NhcmFjdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY2MuZGVzY3JpcGNpb24gQVMgZGVzX2NhcmFjdCwgbm4uZGVzY3JpcGNpb24gQVMgZGVzX25pdmVsLCB4eC5pZF9uaXZlbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeHguaWRfem9uYSwgenouZGVzY3JpcGNpb24gQVMgRXhwcjEsIHp6LmRlc2NyaXBjaW9uMiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0FTVChJU05VTEwoKFNFTEVDVCBTVU0obWF4KSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgIEZST00oU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjIE9OIGMuaWRfdHJhbnMgPSB0LmlkX3RyYW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHQubWF4IElTIE5PVCBOVUxMKSBBTkQgKHQuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICh0LmlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSBBTkQgKHQuaWRfdGlwb19wcmVndW50YSBJTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGMuaWRfdGlwb19wcmVndW50YSAgRlJPTSB0aXBvX3ByZWd1bnRhX3JldGFhIEFTDQogICAgICAgICAgICAgICAgICAgICAgICAgIHAgTEVGVCBPVVRFUiBKT0lOICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSBBUw0KICAgICAgICAgICAgICAgICAgICAgICAgICBjIE9OIHAuaWQgPSBjLmlkX3RpcG9fcHJlZ3VudGEgV0hFUkUgKHAuaWRfZmlsdHJvIElODQogICAgICAgICAgICAgICAgICAgICAgICAgIChjYy5pZF90aXBvX3ByZWd1bnRhKSkgQU5EIChjLmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBjLmlkX3RpcG9fcHJlZ3VudGEpKSBBTkQgKHQubml2ZWwgPSB4eC5pZF9uaXZlbCkgQU5EICh0Lm1heF9lc3RhZG8gPSAxKSBBTkQgKHQuaWRfY2FyYWN0ID0gY2MuaWRfY2FyYWN0XzIpIEFORCAodC5lc3RhZG9fbml2ZWwgPSAxKSBBTkQgKGMuaWRfem9uYSA9IHh4LmlkX3pvbmEpIEFORA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoZXN0YWRvID0gMSkgQU5EIChpZF90cmFucyA9IHQuaWRfdHJhbnMpKSA+IDApKSBBUyBhXzIpLCAwKSBBUyBERUNJTUFMKDEwLCAyKSkgQVMgQWx0b19Qcm9tZWRpb19tYXgsICdodHRwOi8vYmMtc2VsbG9zL1BydWViYVJldGFhL3BvcF91cF9YX3J1YnJvcy5hc3B4P3Bhcj0nICsgQ0FTVChAaWRfY2FtcGHDsWEgQVMgbnZhcmNoYXIoMSkpIA0KICAgICAgICAgICAgICAgICAgKyAnOycgKyBDQVNUKHh4LmlkX2dyYW5vIEFTIG52YXJjaGFyKDIpKSArICc7JyArIENBU1QoeHguaWRfem9uYSBBUyBudmFyY2hhcigyKSkgKyAnOycgKyBDQVNUKGNjLmlkX3RpcG9fcHJlZ3VudGEgQVMgbnZhcmNoYXIoMikpICsgJzsnICsgQ0FTVChjYy5pZF9jYXJhY3RfMiBBUyBudmFyY2hhcigzKSkgKyAnOycgKyBDQVNUKHh4LmlkX25pdmVsIEFTIG52YXJjaGFyKDMpKSArICc7JyArICcwJyBBUyBVUkwsIA0KICAgICAgICAgICAgICAgICAgQ0FTVChJU05VTEwNCiAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBTVU0obWluKSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgKFNFTEVDVCBJU05VTEwodC5taW4sIDApIEFTIG1pbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyBBUyB0IExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgYyBPTiBjLmlkX3RyYW5zID0gdC5pZF90cmFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHQubWluIElTIE5PVCBOVUxMKSBBTkQgKHQuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykgQU5EICh0LmlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSBBTkQgKHQuaWRfdGlwb19wcmVndW50YSBJTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGMuaWRfdGlwb19wcmVndW50YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIHRpcG9fcHJlZ3VudGFfcmV0YWEgQVMgcCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhIEFTIGMgT04gcC5pZCA9IGMuaWRfdGlwb19wcmVndW50YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAocC5pZF9maWx0cm8gPSBjYy5pZF90aXBvX3ByZWd1bnRhKSBBTkQgKGMuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdST1VQIEJZIGMuaWRfdGlwb19wcmVndW50YSkpIEFORCAodC5uaXZlbCA9IHh4LmlkX25pdmVsKSBBTkQgKHQubWluX2VzdGFkbyA9IDEpIEFORCAodC5pZF9jYXJhY3QgPSBjYy5pZF9jYXJhY3RfMikgQU5EICh0LmVzdGFkb19uaXZlbCA9IDEpIEFORCAoYy5pZF96b25hID0geHguaWRfem9uYSkgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYV83DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoZXN0YWRvID0gMSkgQU5EIChpZF90cmFucyA9IHQuaWRfdHJhbnMpKSA+IDApKSBBUyBhXzJfMSksIDApIEFTIERFQ0lNQUwoMTAsIDIpKSBBUyBBbHRvX1Byb21lZGlvX21pbiwgSVNOVUxMDQogICAgICAgICAgICAgICAgICAgICAgKChTRUxFQ1QgU1VNKG1heF9udWxsKSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgKFNFTEVDVCAoQ0FTRSBXSEVOIHBvcmNfYXBsaWMgSVMgTlVMTCBUSEVOIElTTlVMTCh0IC5tYXgsIDApIEVMU0UgSVNOVUxMKHQgLm1heCwgMCkgKiBwb3JjX2FwbGljIC8gMTAwIEVORCkgQVMgbWF4X251bGwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGMgT04gYy5pZF90cmFucyA9IHQuaWRfdHJhbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgICh0LmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pIEFORCAodC5pZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkgQU5EICh0LmlkX3RpcG9fcHJlZ3VudGEgSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBjLmlkX3RpcG9fcHJlZ3VudGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICB0aXBvX3ByZWd1bnRhX3JldGFhIEFTIHAgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSBBUyBjIE9OIHAuaWQgPSBjLmlkX3RpcG9fcHJlZ3VudGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHAuaWRfZmlsdHJvID0gY2MuaWRfdGlwb19wcmVndW50YSkgQU5EIChjLmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBjLmlkX3RpcG9fcHJlZ3VudGEpKSBBTkQgKHQubml2ZWwgPSB4eC5pZF9uaXZlbCkgQU5EICh0Lm1heF9lc3RhZG8gPSAxKSBBTkQgKHQuaWRfY2FyYWN0ID0gY2MuaWRfY2FyYWN0XzIpIEFORCAodC5lc3RhZG9fbml2ZWwgPSAxKSBBTkQgKGMuaWRfem9uYSA9IHh4LmlkX3pvbmEpIEFORA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWFfNg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGVzdGFkbyA9IDEpIEFORCAoaWRfdHJhbnMgPSB0LmlkX3RyYW5zKSkgPiAwKSkgQVMgZ2dfMSksIDApIEFTIEFsdG9fUHJvbWVkaW9fbWF4X251bGwsIElTTlVMTA0KICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIFNVTShtYXhfbnVsbCkgLyBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIChTRUxFQ1QgKENBU0UgV0hFTiBwb3JjX2FwbGljIElTIE5VTEwgVEhFTiBJU05VTEwodCAubWluLCAwKSBFTFNFIElTTlVMTCh0IC5taW4sIDApICogcG9yY19hcGxpYyAvIDEwMCBFTkQpIEFTIG1heF9udWxsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhX3RyYW5zIEFTIHQgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjIE9OIGMuaWRfdHJhbnMgPSB0LmlkX3RyYW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhIElODQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgYy5pZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgdGlwb19wcmVndW50YV9yZXRhYSBBUyBwIExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgQVMgYyBPTiBwLmlkID0gYy5pZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChwLmlkX2ZpbHRybyA9IGNjLmlkX3RpcG9fcHJlZ3VudGEpIEFORCAoYy5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgYy5pZF90aXBvX3ByZWd1bnRhKSkgQU5EICh0Lm5pdmVsID0geHguaWRfbml2ZWwpIEFORCAodC5taW5fZXN0YWRvID0gMSkgQU5EICh0LmlkX2NhcmFjdCA9IGNjLmlkX2NhcmFjdF8yKSBBTkQgKHQuZXN0YWRvX25pdmVsID0gMSkgQU5EIChjLmlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKChTRUxFQ1QgQ09VTlQoMSkgQVMgRXhwcjENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhXzUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChlc3RhZG8gPSAxKSBBTkQgKGlkX3RyYW5zID0gdC5pZF90cmFucykpID4gMCkpIEFTIGdnXzFfMSksIDApIEFTIEFsdG9fUHJvbWVkaW9fbWluX251bGwsIGNjLmlkX2luZGljZSwNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGRlc2NyaXBjaW9uDQogICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICB0aXBvX3ByZWd1bnRhX3JldGFhDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgaWRfZmlsdHJvDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIHRpcG9fcHJlZ3VudGFfcmV0YWEgQVMgdGlwb19wcmVndW50YV9yZXRhYV8zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWQgSU4gKGNjLmlkX3RpcG9fcHJlZ3VudGEpKSkpKSBBUyBkZXNfY29uc3VsdGEsIENBU1QNCiAgICAgICAgICAgICAgICAgICAgICAoKChTRUxFQ1QgU1VNKG1heCkgLyBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICAoU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyBBUyB0IExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGMgT04gYy5pZF90cmFucyA9IHQuaWRfdHJhbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgVE9QICgxKSBpZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIGNhcmFjdF9pZF9ncmFubyBBUyBjYXJhY3RfaWRfZ3Jhbm9fMg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpKSkgQU5EICh0Lm5pdmVsID0gMSkgQU5EICh0LmlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpIEFORCAodC5tYXhfZXN0YWRvID0gMSkgQU5EIChjLmlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWFfMg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChlc3RhZG8gPSAxKSBBTkQgKGlkX3RyYW5zID0gdC5pZF90cmFucykpID4gMCkpIEFTIGFfMl8xXzIpICsNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIFNVTShtaW4pIC8gQ09VTlQoMSkgQVMgRXhwcjENCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIChTRUxFQ1QgSVNOVUxMKHQubWluLCAwKSBBUyBtaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyBBUyB0IExFRlQgT1VURVIgSk9JTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjIE9OIGMuaWRfdHJhbnMgPSB0LmlkX3RyYW5zDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgICh0LmlkX2dyYW5vID0geHguaWRfZ3Jhbm8pIEFORCAodC5pZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkgQU5EICh0LmlkX3RpcG9fcHJlZ3VudGEgPQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgVE9QICgxKSBpZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYXJhY3RfaWRfZ3Jhbm8gQVMgY2FyYWN0X2lkX2dyYW5vXzENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWRfY2FyYWN0ID0gZ2cuaWRfZmlsdHJvX2NhcmFjdCkpKSBBTkQgKHQubml2ZWwgPSAxKSBBTkQgKHQuaWRfY2FyYWN0ID0gZ2cuaWRfZmlsdHJvX2NhcmFjdCkgQU5EICh0Lm1pbl9lc3RhZG8gPSAxKSBBTkQgKGMuaWRfem9uYSA9IHh4LmlkX3pvbmEpIEFORA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgoU0VMRUNUIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSBBUyBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhXzENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGVzdGFkbyA9IDEpIEFORCAoaWRfdHJhbnMgPSB0LmlkX3RyYW5zKSkgPiAwKSkgQVMgYV8yXzFfMV8xKSkgLyAyIC8gMTAwICoNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIHN1cGVyZmljaWUNCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFubyBBUyBTdXBlcmZpY2llX3JldGFhX3hfY2FtcGHDsWFfZ3Jhbm9fMQ0KICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9IGdnLmlkX2dyYW5vX3JlcG9ydCkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkpIEFTIERFQ0lNQUwoMTAsIDApKSBBUyBzdXBlcmZpY2llXzIsIENBU1QNCiAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBzdXBlcmZpY2llDQogICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vDQogICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9IGdnLmlkX2dyYW5vX3JlcG9ydCkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkpIEFTIERFQ0lNQUwoMTAsIDApKSBBUyBzdXBlcmZpY2llLCB6ei5pbmRpY2UsDQogICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBTVU0obWF4KSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICAoU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgYyBPTiBjLmlkX3RyYW5zID0gdC5pZF90cmFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyA9IHh4LmlkX2dyYW5vKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhID0gMikgQU5EICh0Lm5pdmVsID0geHguaWRfbml2ZWwpIEFORCAodC5pZF9jYXJhY3QgPSA0KSBBTkQgKHQubWF4X2VzdGFkbyA9IDEpIEFORCAoYy5pZF96b25hID0geHguaWRfem9uYSkgQU5EDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKChTRUxFQ1QgQ09VTlQoMSkgQVMgRXhwcjENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIEFTIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWFfNA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoZXN0YWRvID0gMSkgQU5EIChpZF90cmFucyA9IHQuaWRfdHJhbnMpKSA+IDApKSBBUyBhXzJfMV8xKSBBUyBBbHRvX1Byb21lZGlvX21heF9kaXN0cmlidWNpb24sDQogICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBTVU0obWF4KSAvIENPVU5UKDEpIEFTIEV4cHIxDQogICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICAoU0VMRUNUIElTTlVMTCh0Lm1heCwgMCkgQVMgbWF4DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWFfdHJhbnMgQVMgdCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgYyBPTiBjLmlkX3RyYW5zID0gdC5pZF90cmFucw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAodC5pZF9ncmFubyBJTg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgSURfTUFQQQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgVGlwb19ncmFub19yZXBvcnRlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZCA9IGdnLmlkX2dyYW5vX3JlcG9ydCkpKSBBTkQgKHQuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpIEFORCAodC5pZF90aXBvX3ByZWd1bnRhID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIFRPUCAoMSkgaWRfdGlwb19wcmVndW50YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgY2FyYWN0X2lkX2dyYW5vIEFTIGNhcmFjdF9pZF9ncmFub18yDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpKSkgQU5EICh0Lm5pdmVsID0gMSkgQU5EICh0LmlkX2NhcmFjdCA9IGdnLmlkX2ZpbHRyb19jYXJhY3QpIEFORCAodC5tYXhfZXN0YWRvID0gMSkgQU5EIChjLmlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKFNFTEVDVCBDT1VOVCgxKSBBUyBFeHByMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEgQVMgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYV8yDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChlc3RhZG8gPSAxKSBBTkQgKGlkX3RyYW5zID0gdC5pZF90cmFucykpID4gMCkpIEFTIGFfMl8xXzJfMSkgKg0KICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1Qgc3VwZXJmaWNpZQ0KICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vIEFTIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFub18xDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2dyYW5vID0gZ2cuaWRfZ3Jhbm9fcmVwb3J0KSBBTkQgKGlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQgKGlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSkgLyAxMDAgQVMgc3VwZXJmaWNpZV8zLA0KICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgcHJpbWVyYQ0KICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vIEFTIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFub18yDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2dyYW5vID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1QgaWRfZ3Jhbm9fcmVwb3J0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFRpcG9fZ3Jhbm8gQVMgVGlwb19ncmFub18yDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgV0hFUkUgICAoaWQgPSB4eC5pZF9ncmFubykpKSBBTkQgKGlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSBBTkQgKGlkX3pvbmEgPSB4eC5pZF96b25hKSkgKg0KICAgICAgICAgICAgICAgICAgICAgIChTRUxFQ1Qgc3VwZXJmaWNpZQ0KICAgICAgICAgICAgICAgICAgICAgICBGUk9NICAgICAgU3VwZXJmaWNpZV9yZXRhYV94X2NhbXBhw7FhX2dyYW5vIEFTIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFub18zDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkX2dyYW5vID0gZ2cuaWRfZ3Jhbm9fcmVwb3J0KSBBTkQgKGlkX3pvbmEgPSB4eC5pZF96b25hKSBBTkQgKGlkX2NhbXBhw7FhID0gQGlkX2NhbXBhw7FhKSkgLyAxMDAgQVMgUGFzX3ByaW1lcmFfc3VwZXJmaWNpZSwNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIHNlZ3VuZGENCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFubyBBUyBTdXBlcmZpY2llX3JldGFhX3hfY2FtcGHDsWFfZ3Jhbm9fMQ0KICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIGlkX2dyYW5vX3JlcG9ydA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZST00gICAgICBUaXBvX2dyYW5vIEFTIFRpcG9fZ3Jhbm9fMQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKGlkID0geHguaWRfZ3Jhbm8pKSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkpICoNCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIHN1cGVyZmljaWUNCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFN1cGVyZmljaWVfcmV0YWFfeF9jYW1wYcOxYV9ncmFubyBBUyBTdXBlcmZpY2llX3JldGFhX3hfY2FtcGHDsWFfZ3Jhbm9fNA0KICAgICAgICAgICAgICAgICAgICAgICBXSEVSRSAgIChpZF9ncmFubyA9IGdnLmlkX2dyYW5vX3JlcG9ydCkgQU5EIChpZF96b25hID0geHguaWRfem9uYSkgQU5EIChpZF9jYW1wYcOxYSA9IEBpZF9jYW1wYcOxYSkpIC8gMTAwIEFTIHBhc19zZWd1bmRhX3N1cGVyZmljaWUsIGNjLnRpcG9fdW5pZGFkLCBDQVNFIFdIRU4gY2MuaWRfdGlwb19wcmVndW50YSA9IDcgT1INCiAgICAgICAgICAgICAgICAgIGNjLmlkX3RpcG9fcHJlZ3VudGEgPSA2IFRIRU4NCiAgICAgICAgICAgICAgICAgICAgICAoU0VMRUNUIFRPUCAoMSkgQ29lZmljaWVudGUNCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIFRpcG9fY2FyYWN0ZXJpc3RpY2FzX3JldGFhDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgaWRfY2FyYWN0ID0gY2MuaWRfY2FyYWN0KSBFTFNFICctMScgRU5EIEFTIGNvZWZpY2llbnRlLCBsLmRlc2NyaXBjaW9uIEFTIGNhbXBhw7FhDQpGUk9NICAgICBHcmFub3Nfem9uYXNfcmV0YWEgQVMgeHggTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX3pvbmFfcmV0YWEgQVMgenogT04geHguaWRfem9uYSA9IHp6LmlkX3pvbmEgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX25pdmVsIEFTIG5uIE9OIHh4LmlkX25pdmVsID0gbm4uaWRfbml2ZWwgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX2dyYW5vIEFTIGdnIE9OIHh4LmlkX2dyYW5vID0gZ2cuaWQgTEVGVCBPVVRFUiBKT0lODQogICAgICAgICAgICAgICAgICBUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSBBUyBjYyBPTiB4eC5pZF9ncmFubyA9IGNjLmlkX2dyYW5vIEFORCBjYy5pZF90aXBvX3ByZWd1bnRhIElODQogICAgICAgICAgICAgICAgICAgICAgKFNFTEVDVCBjLmlkX3RpcG9fcHJlZ3VudGENCiAgICAgICAgICAgICAgICAgICAgICAgRlJPTSAgICAgIHRpcG9fcHJlZ3VudGFfcmV0YWEgQVMgcCBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgQVMgYyBPTiBwLmlkID0gYy5pZF90aXBvX3ByZWd1bnRhDQogICAgICAgICAgICAgICAgICAgICAgIFdIRVJFICAgKHAuaWRfZmlsdHJvIElOIChAaWRfY29uc3VsdGEpKSBBTkQgKGMuaWRfZ3Jhbm8gPSB4eC5pZF9ncmFubykNCiAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgYy5pZF90aXBvX3ByZWd1bnRhKSBMRUZUIE9VVEVSIEpPSU4NCiAgICAgICAgICAgICAgICAgIEHDsW9fY2FtcGHDsWFzIEFTIGwgT04gY2MuaWRfY2FtcGHDsWEgPSBsLmlkDQpXSEVSRSAgKHh4LmlkX2dyYW5vIElOIChAaWRfZ3Jhbm8pKSBBTkQgKHh4LmlkX3pvbmEgSU4gKEBpZF96b25hKSkgQU5EICh4eC5pZF9uaXZlbCBJTiAoQGlkX25pdmVsKSkgQU5EIChjYy5pZF9jYXJhY3RfMiA8PiAxMDQpIEFORCAoY2MuaWRfY2FyYWN0XzIgPD4gMTA1KSBBTkQgKGNjLmlkX2NhcmFjdF8yIDw+IDEwNikgQU5EIChjYy5pZF9jYXJhY3RfMiA8PiAxMDcpIEFORCAoY2MuaWRfY2FyYWN0XzIgPD4gMTA4KSBBTkQgDQogICAgICAgICAgICAgICAgICAoY2MuaWRfY2FyYWN0XzIgPD4gNjUpIEFORCAoY2MuaWRfY2FtcGHDsWEgPSBAaWRfY2FtcGHDsWEpOyIpDQoNCg0KY29uc3VsdGFfUnViZW4NCmBgYA0KDQojIyMgUGFxdWV0ZSBgREJJYA0KDQpEQkkgcGVybWl0ZSBjb25lY3Rhcm5vIGEgbGEgYmFzZSBkZSBkYXRvcyBkZSBTUUwuIFBhcmEgaGFjZXJsbyBkZWJlbW9zIGNvbmZpZ3VyYXIgbG9zIGNhbXBvcy4gTGEgY29uZXhpw7NuIHNlIHB1ZWRlIHZlcmlmaWNhciBlbiBlbCBwYW5lbCBzdXBlcmlvciBkZXJlY2hvLg0KDQpMYSBiYXNlIGRhdG9zIGRlbCBSZVRBQSBlc3RhIGNvbXB1ZXN0YSBwb3IgNiB0YWJsYXMgcHJpbmNpcGFsZXMgIkHDsW8gQ2FtcGHDsWFzIiwgImNhYmVjZXJhX3RybnNhY2Npb25lc19yZXRhYSIsICAiY2FyYWN0X2lkX2dyYW5vIiwgImNhcmFjdF9pZF9ncmFub19jYW1wYcODwrFhX3Zpc3RhIiwgIkNvbGFib3JhZG9yZXMiICB5ICJHcmFub3Nfem9uYXNfcmV0YWEiLg0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KI01lIGNvbmVjdG8gYSBsYSBiYXNlDQpjb24gPC0gREJJOjpkYkNvbm5lY3Qob2RiYzo6b2RiYygpLA0KICAgICAgICAgICAgICAgICAgICAgIERyaXZlciAgICA9ICJTUUwgU2VydmVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgU2VydmVyICAgID0gIkJDLVJFVEEiLA0KICAgICAgICAgICAgICAgICAgICAgIERhdGFiYXNlICA9ICJFc3RpbWFjaW9uZXNfY29waWEiLA0KICAgICAgICAgICAgICAgICAgICAgIFVJRCAgICAgICA9ICJlc3RpbWFjaW9uZXNfY29uc3VsdGEiLA0KICAgICAgICAgICAgICAgICAgICAgIFBXRCAgICAgICA9ICJFc3RpLmJjLjIwMTkyMyIsDQogICAgICAgICAgICAgICAgICAgICAgUG9ydCAgICAgID0gMTQzMywNCiAgICAgICAgICAgICAgICAgICAgICBkYm5hbWUgPSAiRXN0aW1hY2lvbmVzX0NvcGlhIiwNCiAgICAgICAgICAgICAgICAgICAgICBlbmNvZGluZyA9ICJsYXRpbjEiKQ0KDQpEQkk6OmRiTGlzdFRhYmxlcyhjb24pWzE6Nl0jbGlzdGEgZGUgbGFzIHRhYmxhcyBkZSBsYSBiYXNlDQpgYGANCiANCmxhIGZ1bmNpw7NuIGB0YmxgIGRlIGBkcGx5cmAgdHJhZSBsYXMgdGFibGFzIGRlIGxhIGJhc2UgZGUgZGF0b3MuIFRhbWJpZW4gcG9kZW1vcyBhcGxpY2FyIGEgZXN0YSB0YWJsYSB0b2RhcyBsYXMgZnVuY2lvbmVzIHF1ZSB2aW1vcyBlbiBsYXMgY2xhc2VzIHByZXZpYXMuDQoNClZlYW1vcyBhbGd1bmFzIGRlIGxhcyB0YWJsYXMgcXVlIGNvbmZvcm1hbiBsYSBiYXNlIGRlbCBSZVRBQS4NCg0KDQojIyMjIFRhYmxhIFRpcG9fZ3Jhbm8NCmBgYHtyLCBlY2hvPVRSVUV9DQojVGFibGEgaWQgZ3Jhbm8NClRpcG9fZ3Jhbm8gPC0gIHRibChjb24sIGMoIlRpcG9fZ3Jhbm8iKSkgJT4lIA0KICBzZWxlY3QoaWQsZGVzY3JpcGNpb24pICU+JSByZW5hbWUoaWRfZ3Jhbm8gPSBpZCwgZGVzY3JpcGNpb25fZ3Jhbm8gPSBkZXNjcmlwY2lvbikgJT4lIGZpbHRlcihpZF9ncmFubz4wKQ0KVGlwb19ncmFubyANCmBgYA0KDQojIyMjIFRhYmxhIEHDsW9fY2FtcGHDsWFzDQpgYGB7ciwgZWNobz1UUlVFfQ0KI3NlbGVjY2lvbm8gdGFibGEgaWQgY2FtcGHDsWENCkFuaW9fY2FtcGFuaWFzIDwtICB0YmwoY29uLCBjKCJBw7FvX2NhbXBhw7FhcyIpKSAlPiUgcmVuYW1lKGlkX2NhbXBhbmlhID0gaWQsIGRlc2NyaXBjaW9uX2NhbXBhbmlhID0gZGVzY3JpcGNpb24pICU+JSBmaWx0ZXIoaWRfY2FtcGFuaWE+MCkNCg0KQW5pb19jYW1wYW5pYXMgDQpgYGANCg0KIyMjIyBUYWJsYSBUaXBvX3pvbmFfcmV0YWENCmBgYHtyLCBlY2hvPVRSVUV9DQojY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYQ0KVGlwb196b25hX3JldGFhIDwtIHRibChjb24sIGMoIlRpcG9fem9uYV9yZXRhYSIpKSAlPiUgc2VsZWN0KGlkX3pvbmEsZGVzY3JpcGNpb24sZGVzY3JpcGNpb24yKSAlPiUgcmVuYW1lKGRlc2NyaXBjaW9uX3pvbmFfcmV0YWEgPSBkZXNjcmlwY2lvbiwNCiAgICAgICBkZXNjcmlwY2lvbl96b25hX3JldGFhMiA9IGRlc2NyaXBjaW9uMikNClRpcG9fem9uYV9yZXRhYSAgJT4lIGhlYWQoMTApDQpgYGANCg0KDQoNCiMjIyMgVGFibGEgY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYQ0KYGBge3IsIGVjaG89VFJVRX0NCiNjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhDQpjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIDwtIHRibChjb24sIGMoImNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEiKSkgJT4lIHNlbGVjdChpZF90cmFucyxpZF9jb2xhYm9yYWRvcixlc3RhZG8pDQpjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhICAlPiUgaGVhZCgxMCkNCmBgYA0KDQojIyMjIFRhYmxhIHRpcG9fcHJlZ3VudGFfcmV0YWENCmBgYHtyLCBlY2hvPVRSVUV9DQojY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYQ0KdGlwb19wcmVndW50YV9yZXRhYSA8LSB0YmwoY29uLCBjKCJ0aXBvX3ByZWd1bnRhX3JldGFhIikpICU+JSANCiAgc2VsZWN0KGlkLGRlc2NyaXBjaW9uKSAlPiUgcmVuYW1lKGlkX3ByZWd1bnRhID0gaWQsIGRlc2NyaXBjaW9uX3ByZWd1bnRhID0gZGVzY3JpcGNpb24pICU+JSBhc190aWJibGUoKQ0KdGlwb19wcmVndW50YV9yZXRhYQ0KYGBgDQoNCiMjIyMgVGFibGEgdGlwb19jYXJhY3RlcmlzdGljYV9yZXRhYQ0KYGBge3IsIGVjaG89VFJVRX0NCiNjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhDQpUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYSA8LSB0YmwoY29uLCBjKCJUaXBvX2NhcmFjdGVyaXN0aWNhc19yZXRhYV90cmFucyIpKQ0KVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWENCmBgYA0KDQoNCiMjIyMgVGFibGEgQ29sYWJvcmFkb3Jlcw0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KI1RhYmxhIENvbGFib3JhZG9yZXMNCkNvbGFib3JhZG9yZXMgPC0gdGJsKGNvbiwgYygiQ29sYWJvcmFkb3JlcyIpKQ0KQ29sYWJvcmFkb3JlcyAlPiUgdmFyaWFibGUubmFtZXMoKQ0KYGBgDQoNClRhbWJpZW4gcG9kZW1vcyB2aXN1YWxpemFyIGxhcyBjb25leHhpb25lcyBlbnRyZSBsYXMgdGFibGFzIGNvbiBlbCBwYXF1ZXRlIGBkYXRhbW9kZWxyYCBxdWUgbm9zIHBlcm1pdGUgY29uc3RydWlyIGRpYWdyYW1hcyBlbnRpZGFkLXJlYWxhY2nDs24NCg0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTl9DQpsaWJyYXJ5KGRhdGFtb2RlbHIpICNwYXF1ZXRlIHBhcmEgYXJtYXIgZGlhZ3JhbWEgZGUgZW50aWRhZCByZWxhY2lvbg0KDQpjb25lY2Npb24gPC0gb2RiY0RyaXZlckNvbm5lY3QoDQogIGNvbm5lY3Rpb24gPSAiRHJpdmVyPVNRTCBTZXJ2ZXI7IFNlcnZlcj1CQy1SRVRBOyBEYXRhYmFzZT1Fc3RpbWFjaW9uZXNfY29waWE7IFVJRD1lc3RpbWFjaW9uZXNfY29uc3VsdGE7IFB3ZD1Fc3RpLmJjLjIwMTkyMyINCiAgKQ0KDQpzUXVlcnkgPC0gZG1fcmVfcXVlcnkoInNxbHNlcnZlciIpDQpkbV9yZXRhYSA8LSBzcWxRdWVyeShjaGFubmVsID0gY29uZWNjaW9uLCBzUXVlcnksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwgZXJyb3JzPVRSVUUpDQpkbV9yZXRhYSA8LSBhcy5kYXRhX21vZGVsKGRtX3JldGFhKSAjcGFzbyBhIGZvcm1hdG8gbW9kZWxvDQoNCmZvY3VzIDwtbGlzdCh0YWJsZXMgID0gYygiQcOxb19jYW1wYcOxYXMiLCJjYWJlY2VyYV90cmFuc2FjY2lvbmVzX3JldGFhIiwiY2FyYWN0X2lkX2dyYW5vIiwgICAgICAgICAgICAgICANCiJjYXJhY3RfaWRfZ3Jhbm9fY2FtcGHDsWFfdmlzdGEiLCJDb2xhYm9yYWRvcmVzIiwiR3Jhbm9zX3pvbmFzX3JldGFhIikpIA0KIA0KZ3JhcGggPC0gZG1fY3JlYXRlX2dyYXBoKGRtX3JldGFhICwgcmFua2RpciA9ICJCVCIsIGZvY3VzID0gZm9jdXMsIGNvbF9hdHRyID0gYygiY29sdW1uIiwgInR5cGUiKSkgDQpkbV9yZW5kZXJfZ3JhcGgoZ3JhcGgpICNncmFmaWNvDQpgYGANCg0KDQojIyMgUXVlcnkgU1FMIHZzIGRwbHlyDQoNCkVuIGVzdGEgc2VjY2lvbiB2YW1vcyBhIHJlcGxpY2FyIGxhIGNvbnN1bHRhIFNRTCBxdWUgdmltb3MgYXJyaWJhIHBlcm8gZW4gZm9tcmF0byBkcGx5ci4gVmFtb3MgYSB2ZXIgcXVlIHVuYSBjb25zdWx0YSBtdXkgZXh0ZW5zYSBzZSBwdWVkZSByZWFsaXphciBlbiB1bmEgZm9tcmEgbcOhcyBwcm9saWphIHkgYnJldmUuDQoNCkVsIGNvbWFuZG9gc2hvd19xdWVyeWAgcGVybWl0ZSBleHRyYWVyIGxhIGNvbnN1bHRhIGVuIGZvcm1hdG8gU1FMLg0KDQpgYGB7ciBlY2hvPVRSVUV9DQp0YWJsYV9jb25zdWx0YV9zcWwgPC0gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgJT4lICANCiAgbGVmdF9qb2luKGNhYmVjZXJhX3RyYW5zYWNjaW9uZXNfcmV0YWEsYnkgPSBjKCJpZF90cmFucyIsImlkX2NvbGFib3JhZG9yIikpICU+JSAjam9pbiBjb24gdGFibGEgY2FiZWNlcmENCiAgbGVmdF9qb2luKFRpcG9fZ3Jhbm8gLGJ5ID0gImlkX2dyYW5vIikgJT4lDQogIGxlZnRfam9pbihBbmlvX2NhbXBhbmlhcyAsYnkgPSBjKCJpZF9jYW1wYcOxYSI9ImlkX2NhbXBhbmlhIikgKSAlPiUNCiAgbGVmdF9qb2luKFRpcG9fem9uYV9yZXRhYSwgYnkgPSBjKCJpZF96b25hIikgICkgJT4lIA0KICBmaWx0ZXIoaWRfY2FtcGHDsWEgPT0gOSxpZF96b25hPT01LG5pdmVsPT0xLGlkX2dyYW5vPT0xLA0KICAgICAgICAgaWRfdGlwb19wcmVndW50YT09NiwgbWF4X2VzdGFkbyA9PSAxLCBlc3RhZG89PTEpICU+JQ0KICBncm91cF9ieShkZXNjcmlwY2lvbl9ncmFubywgaWRfZ3Jhbm8sIGRlc2NyaXBjaW9uX2NhbXBhbmlhLCBpZF9jYW1wYcOxYSwgZGVzY3JpcGNpb25fem9uYV9yZXRhYSwgaWRfem9uYSwNCiAgICAgICAgICBuaXZlbCwgaWRfdGlwb19wcmVndW50YSwgaWRfY2FyYWN0LGRlc2NyaXBjaW9uKSAlPiUgDQogIHN1bW1hcmlzZShwcm9tZWRpb19tYXggPSByb3VuZChtZWFuKG1heCwgbmEucm0gPSBUKSwyKSwNCiAgICAgICAgICAgIHByb21lZGlvX21pbiA9IHJvdW5kKG1lYW4obWluLCBuYS5ybSA9IFQpLDIpKSANCg0KdGFibGFfY29uc3VsdGFfc3FsICU+JSBkcGx5cjo6c2hvd19xdWVyeSgpICN2ZXIgcXVlcnkgU1FMDQoNCnRhYmxhX2NvbnN1bHRhX3NxbCAjc2FsaWRhDQpgYGANCg0KIyMjIFBsYW50ZW9zIFRlY25vbG9naWNvcw0KDQpDb25zdHJ1aXIgbG9zIHBsYW50ZW9zIHRlY25vbMOzZ2ljb3Mgc3VlbGUgc2VyIHVuIHRyYWJham8gcXVlIHRlZGlvc28gcXVlIG5vIGVzdGEgYXV0b21hdGl6YWRvIHkgc3VlbGUgdG9tYXIgYmFzdGFudGUgdGllbXBvLiBFbiBlc3RhIHNlY2Npw7NuIGJ1c2NhbW9zIGF1dG9tYXRpemFyIGxhIGNvbnN0cnVjY2nDs24gZGUgbG9zIHBsYW50ZW9zLg0KDQoNCmBgYHtyIGVjaG89VFJVRX0NCiMgdGFibGEgY29uIHRvZGFzIGxvcyBpbnN1bW9zIGluY2x1aWRvcyBlbiBsYSBiYXNlDQp0YWJsYV92YXJpYWJsZXMgPC0gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgJT4lIGRpc3RpbmN0KGRlc2NyaXBjaW9uLHRpcG9fdW5pZGFkKSAlPiUgYXNfdGliYmxlKCkNCg0KI2xpc3RhIGRlIHZhcmlhYmxlcyBpbmNsdWlkYXMNCnZhcmlhYmxlc19wbGFudGVvIDwtIGMoIkFkb3BjacOzbiBkZSBOVCIsIm1heF9taW4iLCJuaXZlbCIsImlkX2NhbXBhw7FhIiwiaWRfZ3Jhbm8iLCJpZF96b25hIiwNCiAgICAgICAgICAgICAgICAgICAgICAgImRlc2NyX2dyYW5vIiwiZGVzY3JfY2FtcGFuaWEiLCJTZW1pbGxhIiwiVXJlYSIsIlBEQSIsDQogICAgICAgICAgICAgICAgICAgICAgICJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBCYXJiZWNobyIsDQogICAgICAgICAgICAgICAgICAgICAgICJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBjdWx0aXZvIiwiSGliLiBSUiBCdDIiLCIyLTREIiwiRGljYW1iYSIsDQogICAgICAgICAgICAgICAgICAgICAgICJNZXRzdWxmdXLDs24iLA0KICAgICAgICAgICAgICAgICAgICAgICAiU1BTIiwiQXRyYXppbmEiLCJNZXRvbGFjbG9yIiwiUGljbG9yw6FtIiwiRGlhbWlkYXMiLCJEaWNsb3N1bGFtIiwgDQogICAgICAgICAgICAgICAgICAgICAgICJGdW5naWNpZGEgMSAoRXN0cm9iLiArIFRyaWF6b2wpIiwiU2VtaWxsYSIsICJJbm9jLiArIEZ1bmdpYy4iLA0KICAgICAgICAgICAgICAgICAgICAgICAiSW5vY3VsYW50ZSAxIChmdWxsKSIsIkZvc2ZvcmFkb3MgMSIsICJGb3Nmb3JhZG9zIDIiLA0KICAgICAgICAgICAgICAgICAgICAgICAiQ3VyYXNlbWlsbGEgLSBGdW5naWNpZGEgYmFzZSIsIkNsb3JpbXVyw7NuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIlBNQSIsIkRpbWV0b2F0byIsICJDdXJhc2VtaWxsYSAyIC0gRnVuZ2ljaWRhIiwNCiJDdXJhc2VtaWxsYSAyIC0gZnVuZ2ljLiIsIgkNCkZ1bmdpY2lkYSAyIikNCmBgYA0KDQoNCg0KYGBge3J9DQojQXJtbyBsYSBjb25zdWx0YSBkZSBwbGFudGVvcw0KcGxhbnRlb3MgPC0gVGlwb19jYXJhY3RlcmlzdGljYXNfcmV0YWEgJT4lICANCiAgZmlsdGVyKGRlc2NyaXBjaW9uICVpbiUgdmFyaWFibGVzX3BsYW50ZW8pICU+JSAjbWUgcXVlZG8gY29uIGluc3Vtb3MgaW5jbHVpZG9zIGVuIGxvcyBwbGFudGVvcw0KICBsZWZ0X2pvaW4oY2FiZWNlcmFfdHJhbnNhY2Npb25lc19yZXRhYSwgYnkgPSBjKCJpZF90cmFucyIsImlkX2NvbGFib3JhZG9yIikpICU+JSANCiAgbGVmdF9qb2luKFRpcG9fem9uYV9yZXRhYSwgYnk9YygiaWRfem9uYSIpKSAlPiUgDQogIGxlZnRfam9pbihUaXBvX2dyYW5vLCBieT0iaWRfZ3Jhbm8iKSAlPiUNCiAgI2xlZnRfam9pbih0aXBvX3ByZWd1bnRhX3JldGFhLCBieSA9IGMoImlkX3RpcG9fcHJlZ3VudGEiPSAiaWRfcHJlZ3VudGEiKSkgJT4lIA0KICBsZWZ0X2pvaW4oQW5pb19jYW1wYW5pYXMsYnk9YygiaWRfY2FtcGHDsWEiPSJpZF9jYW1wYW5pYSIgKSkgJT4lDQogIGZpbHRlcihlc3RhZG89PTEpICU+JSAjZW5jdWVzdGFzIHZhbGlkYWRhcw0KICAjY29ycmVjaW9uIG1haXogdGFyZGlvIHBvciBjYXJnYSByZXRhYQ0KICBtdXRhdGUoaWRfZ3Jhbm8gPSBjYXNlX3doZW4oIChpZF9ncmFubz09OCAmIGlkX3pvbmEgJWluJSBjKDEsMiwxNikgKX4gNywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVCB+IGFzLmRvdWJsZShpZF9ncmFubykgKSwNCiAgICAgICAgIGRlc2NyaXBjaW9uX2dyYW5vID0gaWZlbHNlKGlkX2dyYW5vPT03LCAiTWHDrXogMcKwIFRlbXByYW5vIixkZXNjcmlwY2lvbl9ncmFubykNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUobWF4ID0gY2FzZV93aGVuKHRpcG9fdW5pZGFkID09IiUiICYgaXMubmEobWF4KSB+IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgVCB+IGFzLm51bWVyaWMobWF4KSApLA0KICAgICAgICAgbWluID0gY2FzZV93aGVuKHRpcG9fdW5pZGFkID09IiUiICYgaXMubmEobWluKSB+IGFzLm51bWVyaWMobWF4KSwNCiAgICAgICAgIFQgfiBhcy5udW1lcmljKG1pbikNCiAgICAgICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICApICU+JSANCiAgIGdyb3VwX2J5KCBpZF9jYW1wYcOxYSAsZGVzY3JpcGNpb25fY2FtcGFuaWEgLCBuaXZlbCwgDQogICAgICAgICAgICAgaWRfem9uYSwgZGVzY3JpcGNpb25fem9uYV9yZXRhYSwNCiAgICAgICAgICAgICBpZF9ncmFubywgZGVzY3JpcGNpb25fZ3Jhbm8sIGRlc2NyaXBjaW9uKSAlPiUgDQogIHN1bW1hcmlzZShwcm9tZWRpb19tYXggPSBtZWFuKG1heCwgbmEucm0gPSBUKSwgI3Byb21lZGlvIG1heGltbyBhcGxpY2Fkbw0KICAgICAgICAgICAgcHJvbWVkaW9fbWluID0gbWVhbihtaW4sIG5hLnJtID0gVCkgI3Byb21lZGlvIG1pbmltbyBhcGxpY2Fkbw0KICAgICAgICAgICAgI3Byb21lZGlvX3BvcmNfYXBsaWMgPSBtZWFuKHBvcmNfYXBsaWMsIG5hLnJtID0gVCkNCiAgICAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZG9ibGVfbmEgPSBpZmVsc2UoIGlzLm5hKHByb21lZGlvX21heCkgJiBpcy5uYShwcm9tZWRpb19taW4pLDEsMCApKSAlPiUNCiAgZmlsdGVyKGRvYmxlX25hICE9MSkgJT4lIA0KICBtdXRhdGUoIHByb21lZGlvID0gKHByb21lZGlvX21heCsgcHJvbWVkaW9fbWluKS8yKSAlPiUgDQogIHNlbGVjdCgtYyhwcm9tZWRpb19tYXgscHJvbWVkaW9fbWluKSApIA0KICANCg0KDQojRnVuY2lvbiBwYXJhIGVzY2FsYXIgZWwgbml2ZWwgZGUgYWRvcGNpb24gdGVjbm9sb2dpY2ENCiNlc2NhbGFyIDwtIGZ1bmN0aW9uKHgpeyB4ID0geC9zdW0oeCxuYS5ybSA9IFQpICoxMDAgfQ0KDQojR2VuZXJvIGRlc2NyaXBjaW9uIE5pdmVsIFRlY25vbMOzZ2ljbyB5IGVzY2FsbyBBZG9wY2lvbiBkZSBOVA0KcGxhbnRlb3MgPC0gcGxhbnRlb3MgJT4lIGFzX3RpYmJsZSgpICU+JSANCiAgbXV0YXRlKGRlc2NyaXBjaW9uX25pdmVsID0gY2FzZV93aGVuKG5pdmVsID09IDEgfiAiQWx0byIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuaXZlbCA9PSAyIH4gIk1lZGlvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5pdmVsID09IDMgfiAiQmFqbyIpKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBkZXNjcmlwY2lvbix2YWx1ZXNfZnJvbSA9IGMocHJvbWVkaW8pICkgJT4lIA0KICBncm91cF9ieShpZF9jYW1wYcOxYSxpZF96b25hLGlkX2dyYW5vKSMgJT4lDQogICNtdXRhdGUoQWRvcGNpb25fTlQgPSBlc2NhbGFyKGBBZG9wY2nDs24gZGUgTlRgKSkgICAjZXNjYWxvIGEgMTAwIGVsIG5pdmVsIHRlY25vbG9naWNvDQoNCiNQYXNvIGEgZm9ybWF0byBsb25nDQpwbGFudGVvcyA8LSBwbGFudGVvcyAlPiUNCiAgbXV0YXRlKGFkb3BjaW9uX250ID0gYEFkb3BjacOzbiBkZSBOVGApICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtYygiaWRfY2FtcGHDsWEiLCAiZGVzY3JpcGNpb25fY2FtcGFuaWEiLCJuaXZlbCIsImlkX3pvbmEiLCJkZXNjcmlwY2lvbl96b25hX3JldGFhIiAsImlkX2dyYW5vIiwiZGVzY3JpcGNpb25fZ3Jhbm8iLCAiZGVzY3JpcGNpb25fbml2ZWwiLCJhZG9wY2lvbl9udCIpICxuYW1lc190byA9ICJ2YXJpYWJsZXMiLHZhbHVlc190byA9ICJ2YWxvcmVzIikNCg0KVGlwb196b25hX3JldGFhDQpgYGANCg0KDQpgYGB7ciBlY2hvPVRSVUV9DQpwbGFudGVvc19wb25kIDwtIHBsYW50ZW9zICU+JQ0KICBncm91cF9ieShpZF9jYW1wYcOxYSxkZXNjcmlwY2lvbl9jYW1wYW5pYSxpZF96b25hLCBkZXNjcmlwY2lvbl96b25hX3JldGFhLA0KICAgICAgICAgICBpZF9ncmFubyxkZXNjcmlwY2lvbl9ncmFubyx2YXJpYWJsZXMpICU+JQ0KICBmaWx0ZXIoIWlzLm5hKHZhbG9yZXMpICkgJT4lICNlc3RvIGVzIHBhcmEgbm8gY29udGFyIGxvcyBubyBjb250ZXN0YWRvcyB5IGNhbGN1bGFyIGxvcyBwbGFudGVvcyBSZXRhYSAicHJvbWVkaW8gc2ltcGxlIg0KICBzdW1tYXJpc2UodmFsb3JlcyA9ICB3ZWlnaHRlZC5tZWFuKHZhbG9yZXMgLHcgPSBhZG9wY2lvbl9udC8xMDAsbmEucm0gPSBUKQ0KICAgICAgICAgICAgKQ0KYGBgDQoNCiMjIyMgUGxhbnRlb3Mgey50YWJzZXR9DQoNCiMjIyMjIFNvamENCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OX0NCnZhcmlhYmxlc19wbGFudGVvX3NvamEgPC1jKCJTZW1pbGxhIiwgIlNQUyIsIkdsaWZvc2F0byBjb25jZW50cmFkbyAtIEJhcmJlY2hvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBjdWx0aXZvIiwgIjItNEQiLCJDbG9yaW11csOzbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiTWV0c3VsZnVyw7NuIiwiRGljbG9zdWxhbSIsIkRpYW1pZGFzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJFc3Ryb2JpcnVsaW5hICsgVHJpYXpvbCIsIklub2N1bGFudGUgMSAoZnVsbCkiLCJJbm9jLiArIEZ1bmdpYy4iLCJGdW5naWNpZGEgMiIpIA0KDQoNCnBsYW50ZW9fc29qYSA8LSBwbGFudGVvc19wb25kICAlPiUgDQogIGZpbHRlcihkZXNjcmlwY2lvbl9ncmFubz09IlNvamEgMcKwIix2YXJpYWJsZXMgJWluJSB2YXJpYWJsZXNfcGxhbnRlb19zb2phKSAlPiUgdW5ncm91cCgpDQogIA0KICANCnBsYW50ZW9zX3BvbmQgICU+JSANCiAgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iU29qYSAxwrAiLHZhcmlhYmxlcyAlaW4lIHZhcmlhYmxlc19wbGFudGVvX3NvamEpICU+JSANCiAgZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh5PXZhbG9yZXMseD1kZXNjcmlwY2lvbl9jYW1wYW5pYSwgY29sb3I9YXMuZmFjdG9yKGRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpKSkrIA0KICBnZW9tX3BvaW50KCkgKyAgZmFjZXRfd3JhcCh+dmFyaWFibGVzLCBzY2FsZXMgPSAiZnJlZV95IikrDQogIGxhYnModGl0bGUgPSAgIkRvc2lzIGFwbGljYWRhcyAtIFNvamEgMcK6IikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBjb2xvcj0iWm9uYSIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSINCiAgICAgICAgKSANCg0KYGBgDQoNCmBgYHtyfQ0KcGxhbnRlb3MgICU+JSANCiAgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iU29qYSAxwrAiLHZhcmlhYmxlcyAlaW4lIHZhcmlhYmxlc19wbGFudGVvX3NvamEpICU+JSANCiAgZmlsdGVyKGRlc2NyaXBjaW9uX2NhbXBhbmlhPT0iMjAxNy8yMDE4IixkZXNjcmlwY2lvbl96b25hX3JldGFhPT0iSUlJIikNCmBgYA0KDQpgYGB7cn0NCnBsYW50ZW9zICU+JSBmaWx0ZXIodmFyaWFibGVzPT0iQWRvcGNpw7NuIGRlIE5UIikgJT4lIGdyb3VwX2J5KGlkX2dyYW5vLCBkZXNjcmlwY2lvbl9ncmFubywgZGVzY3JpcGNpb25fem9uYV9yZXRhYSxkZXNjcmlwY2lvbl9jYW1wYW5pYSkgJT4lICBzdW1tYXJpc2UoYWRvcGNpb24gPSBzdW0odmFsb3JlcykpDQoNCnBsYW50ZW9zICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fY2FtcGFuaWE9PSIyMDE2LzIwMTciLCBkZXNjcmlwY2lvbl96b25hX3JldGFhPT0iSUlJIiwNCiAgICAgICAgICAgICAgICAgICAgaWRfZ3Jhbm89PTIsIHZhcmlhYmxlcz09IkFkb3BjacOzbiBkZSBOVCIpDQpgYGANCg0KIyMjIyMgVHJpZ28NCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OX0NCnZhcmlhYmxlc19wbGFudGVvX1RyaWdvIDwtYygiU2VtaWxsYSIsIlVyZWEiLCJQTUEiLCJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBCYXJiZWNobyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiMi00RCIsIkRpY2FtYmEiLCAiTWV0c3VsZnVyw7NuIiwiRm9zZm9yYWRvcyAxIiwiRnVuZ2ljaWRhIDEgKEVzdHJvYi4gKyBUcmlhem9sKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiQ3VyYXNlbWlsbGEgMiAtIEZ1bmdpY2lkYSIsIkN1cmFzZW1pbGxhIDIgLSBmdW5naWMuIikgI0xhbWJkYWNpYWxvdHJpbmEgbm8gbG8gZW5jb250csOpDQoNCnBsYW50ZW9fdHJpZ28gPC0gcGxhbnRlb3NfcG9uZCAgJT4lIA0KICBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJUcmlnbyIsdmFyaWFibGVzICVpbiUgdmFyaWFibGVzX3BsYW50ZW9fVHJpZ28pICU+JSB1bmdyb3VwKCkNCiAgDQoNCnBsYW50ZW9zX3BvbmQgICU+JSANCiAgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iVHJpZ28iLHZhcmlhYmxlcyAlaW4lIHZhcmlhYmxlc19wbGFudGVvX1RyaWdvKSAlPiUgDQogIGdncGxvdCguLG1hcHBpbmcgPSBhZXMoeT12YWxvcmVzLHg9ZGVzY3JpcGNpb25fY2FtcGFuaWEsIGNvbG9yPWFzLmZhY3RvcihkZXNjcmlwY2lvbl96b25hX3JldGFhKSkpKyANCiAgZ2VvbV9wb2ludCgpICsgIGZhY2V0X3dyYXAofnZhcmlhYmxlcywgc2NhbGVzID0gImZyZWVfeSIpKw0KICBsYWJzKHRpdGxlID0gICJEb3NpcyBhcGxpY2FkYXMgLSBUcmlnbyIpKw0KICBsYWJzKHg9IkNhbXBhw7FhIiwgY29sb3I9IlpvbmEiKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iDQogICAgICAgICkgDQpgYGANCg0KIyMjIyMgTWFpeg0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCnZhcmlhYmxlc19wbGFudGVvX01haXogPC1jKCAiSGliLiBSUiBCdDIiLCAiVXJlYSIsIlBEQSIsIkdsaWZvc2F0byBjb25jZW50cmFkbyAtIEJhcmJlY2hvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJHbGlmb3NhdG8gY29uY2VudHJhZG8gLSBjdWx0aXZvIiwgIjItNEQiLCJBdHJhemluYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiTWV0b2xhY2xvciIsIlBpY2xvcsOhbSIsIkRpYW1pZGFzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJEaWNhbWJhIiwgIkVzdHJvYmlydWxpbmEgKyBUcmlhem9sIikgI0xhbWJkYWNpYWxvdHJpbmEgbm8gbG8gZW5jb250csOpDQoNCnBsYW50ZW9fbWFpeiA8LSBwbGFudGVvc19wb25kICAlPiUgDQogIGZpbHRlcihkZXNjcmlwY2lvbl9ncmFubz09Ik1hw616IDHCsCBUZW1wcmFubyIsdmFyaWFibGVzICVpbiUgdmFyaWFibGVzX3BsYW50ZW9fTWFpeikgJT4lIHVuZ3JvdXAoKSANCg0KcGxhbnRlb3NfcG9uZCAgJT4lIA0KICBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJNYcOteiAxwrAgVGVtcHJhbm8iLHZhcmlhYmxlcyAlaW4lIHZhcmlhYmxlc19wbGFudGVvX01haXopICU+JSANCiAgZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh5PXZhbG9yZXMseD1kZXNjcmlwY2lvbl9jYW1wYW5pYSwgY29sb3I9YXMuZmFjdG9yKGRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpKSkrIA0KICBnZW9tX3BvaW50KCkgKyAgZmFjZXRfd3JhcCh+dmFyaWFibGVzLCBzY2FsZXMgPSAiZnJlZV95IikrDQogIGxhYnModGl0bGUgPSAgIkRvc2lzIGFwbGljYWRhcyAtIE1haXoiKSsNCiAgbGFicyh4PSJDYW1wYcOxYSIsIGNvbG9yPSJab25hIikrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIg0KICAgICAgICApIA0KDQpgYGANCg0KIyMjIyB7LX0NCg0KR3VhcmRvIHBsYW50ZW9zDQpgYGB7cn0NCmxpYnJhcnkob3Blbnhsc3gpICNhY3RpdmFtb3MgbGEgbGlicmVyw61hDQoNCndyaXRlLnhsc3goeCA9IHBsYW50ZW9zX3BvbmQsIGZpbGUgPSAiZGF0YXNldHMvcGxhbnRlb3MueGxzeCIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCiMjIyMgRXZvbHVjacOzbiBkZWwgbml2ZWwgdGVjbm9sw7NnaWNvIHsudGFic2V0fQ0KDQojIyMjIyBNYWl6IDHCug0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCnBsYW50ZW9zICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJNYcOteiAxwrAgVGVtcHJhbm8iLCB2YXJpYWJsZXM9PSJBZG9wY2nDs24gZGUgTlQiKSAlPiUgDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwgeSA9IHZhbG9yZXMsIGdyb3VwPW5pdmVsLGZpbGwgPSBhcy5mYWN0b3IoZGVzY3JpcGNpb25fbml2ZWwpKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkrICB0aGVtZV9idygpKw0KICBsYWJzKHRpdGxlID0gICJOaXZlbCB0ZWNub2zDs2dpY28gcG9yIHpvbmEgLSBNYcOteiB0ZW1wcmFubyIpKw0KICBsYWJzKHg9IkNhbXBhw7FhIiwgZmlsbD0iTml2ZWwgdGVjbm9sw7NnaWNvIikrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIg0KICAgICAgICApIA0KYGBgDQoNCiMjIyMjIE1haXogVGFyZGlvIHkgMsK6DQpgYGB7ciwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OSwgZWNobz1UUlVFfQ0KcGxhbnRlb3MgJT4lIGZpbHRlcihkZXNjcmlwY2lvbl9ncmFubz09Ik1hw616IDHCsCBUYXJkaW8geSAywrAiLCB2YXJpYWJsZXM9PSJBZG9wY2nDs24gZGUgTlQiKSAlPiUgDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwgeSA9IHZhbG9yZXMsIGdyb3VwPW5pdmVsLGZpbGwgPSBhcy5mYWN0b3IoZGVzY3JpcGNpb25fbml2ZWwpKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkrICB0aGVtZV9idygpKw0KICBsYWJzKHRpdGxlID0gICJOaXZlbCB0ZWNub2zDs2dpY28gcG9yIHpvbmEgLSBNYcOteiB0YXJkw61vIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBmaWxsPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgICAgICkgDQpgYGANCg0KDQojIyMjIyBTb2phDQpgYGB7ciwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OSwgZWNobz1UUlVFfQ0KcGxhbnRlb3MgJT4lIGZpbHRlcihkZXNjcmlwY2lvbl9ncmFubz09IlNvamEgMcKwIiwgdmFyaWFibGVzPT0iQWRvcGNpw7NuIGRlIE5UIikgJT4lIA0KZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh4ID0gZGVzY3JpcGNpb25fY2FtcGFuaWEsIHkgPSB2YWxvcmVzLCBncm91cD1uaXZlbCxmaWxsID0gYXMuZmFjdG9yKGRlc2NyaXBjaW9uX25pdmVsKSkpICsNCiAgZ2VvbV9jb2woKSArDQogIGZhY2V0X3dyYXAofmRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpKyAgdGhlbWVfYncoKSsNCiAgbGFicyh0aXRsZSA9ICAiTml2ZWwgdGVjbm9sw7NnaWNvIHBvciB6b25hIC1Tb2phIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBmaWxsPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgICAgICkgDQoNCmBgYA0KDQojIyMjIyBUcmlnbw0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCnBsYW50ZW9zICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJUcmlnbyIgLCB2YXJpYWJsZXM9PSJBZG9wY2nDs24gZGUgTlQiKSAlPiUgDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwgeSA9IHZhbG9yZXMsIGdyb3VwPW5pdmVsLGZpbGwgPSBhcy5mYWN0b3IoZGVzY3JpcGNpb25fbml2ZWwpKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkrICB0aGVtZV9idygpKw0KICBsYWJzKHRpdGxlID0gICJOaXZlbCB0ZWNub2zDs2dpY28gcG9yIHpvbmEgLVRyaWdvIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBmaWxsPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgICAgICkgDQpgYGANCiMjIyMjIEdpcmFzb2wNCmBgYHtyLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD05LCBlY2hvPVRSVUV9DQpwbGFudGVvcyAlPiUgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iR2lyYXNvbCIgLCB2YXJpYWJsZXM9PSJBZG9wY2nDs24gZGUgTlQiKSAlPiUgDQpnZ3Bsb3QoLixtYXBwaW5nID0gYWVzKHggPSBkZXNjcmlwY2lvbl9jYW1wYW5pYSwgeSA9IHZhbG9yZXMsIGdyb3VwPW5pdmVsLGZpbGwgPSBhcy5mYWN0b3IoZGVzY3JpcGNpb25fbml2ZWwpKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkrICB0aGVtZV9idygpKw0KICBsYWJzKHRpdGxlID0gICJOaXZlbCB0ZWNub2zDs2dpY28gcG9yIHpvbmEgLSBHaXJhc29sIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBmaWxsPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICAgICAgICkgDQpgYGANCiMjIyMjIENlYmFkYQ0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCnBsYW50ZW9zICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJDZWJhZGEiICwgdmFyaWFibGVzPT0iQWRvcGNpw7NuIGRlIE5UIikgJT4lIA0KZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh4ID0gZGVzY3JpcGNpb25fY2FtcGFuaWEsIHkgPSB2YWxvcmVzLCBncm91cD1uaXZlbCxmaWxsID0gYXMuZmFjdG9yKGRlc2NyaXBjaW9uX25pdmVsKSkpICsNCiAgZ2VvbV9jb2woKSArDQogIGZhY2V0X3dyYXAofmRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpKyAgdGhlbWVfYncoKSsNCiAgbGFicyh0aXRsZSA9ICAiTml2ZWwgdGVjbm9sw7NnaWNvIHBvciB6b25hIC1DZWJhZGEiKSsNCiAgbGFicyh4PSJDYW1wYcOxYSIsIGZpbGw9Ik5pdmVsIHRlY25vbMOzZ2ljbyIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCINCiAgICAgICAgKSANCg0KYGBgDQoNCiMjIyMgey19DQoNCiMjIyMgRG9zaXMgZGUgZmVydGlsaXphY2nDs24NCg0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCiNHcmFmaWNvDQpwbGFudGVvcyAlPiUgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iTWHDrXogMcKwIFRlbXByYW5vIiwgdmFyaWFibGVzPT0iVXJlYSIpICAlPiUgICNmaWx0cm8gY3VsdGl2bw0KZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh4ID0gZGVzY3JpcGNpb25fY2FtcGFuaWEsDQogICAgICAgICAgICAgICAgICAgICAgIHkgPSB2YWxvcmVzLCBncm91cD1uaXZlbCxjb2xvciA9IGFzLmZhY3RvcihkZXNjcmlwY2lvbl9uaXZlbCkpKSArDQogIGdlb21fbGluZSgpICsgZ2VvbV9wb2ludCgpKw0KICBmYWNldF93cmFwKH5kZXNjcmlwY2lvbl96b25hX3JldGFhKSArICANCiAgdGhlbWVfYncoKSArDQogIGxhYnModGl0bGUgPSAgIkZlcnRpbGl6YWNpw7NuIGNvbiBVcmVhIChrZy9oYSkgZW4gTWHDrXogdGVtcHJhbm8iKSsNCiAgbGFicyh4PSJDYW1wYcOxYSIsIGNvbG9yPSJOaXZlbCB0ZWNub2zDs2dpY28iKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iDQogICAgICAgICkNCmBgYA0KDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD05LCBlY2hvPVRSVUV9DQojR3JhZmljbw0KcGxhbnRlb3NfcG9uZCAlPiUgZmlsdGVyKGRlc2NyaXBjaW9uX2dyYW5vPT0iTWHDrXogMcKwIFRlbXByYW5vIiwgdmFyaWFibGVzPT0iVXJlYSIpICAlPiUgICNmaWx0cm8gY3VsdGl2bw0KZ2dwbG90KC4sbWFwcGluZyA9IGFlcyh4ID0gZGVzY3JpcGNpb25fY2FtcGFuaWEsDQogICAgICAgICAgICAgICAgICAgICAgIHkgPSB2YWxvcmVzLCBncm91cD0xKSkgKw0KICBnZW9tX2xpbmUoKSArIGdlb21fcG9pbnQoKSsNCiAgZmFjZXRfd3JhcCh+ZGVzY3JpcGNpb25fem9uYV9yZXRhYSkgKyAgDQogIHRoZW1lX2J3KCkgKw0KICBsYWJzKHRpdGxlID0gICJGZXJ0aWxpemFjacOzbiBjb24gVXJlYSAoa2cvaGEpIGVuIE1hw616IHRlbXByYW5vIikrDQogIGxhYnMoeD0iQ2FtcGHDsWEiLCBjb2xvcj0iTml2ZWwgdGVjbm9sw7NnaWNvIikrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIg0KICAgICAgICApDQpgYGANCg0KYGBge3IsIGZpZy5oZWlnaHQ9OSwgZmlnLndpZHRoPTksIGVjaG89VFJVRX0NCiNHcmFmaWNvDQpwbGFudGVvc19wb25kICU+JSBmaWx0ZXIoZGVzY3JpcGNpb25fZ3Jhbm89PSJUcmlnbyIsIHZhcmlhYmxlcz09IlVyZWEiKSAgJT4lICAjZmlsdHJvIGN1bHRpdm8NCmdncGxvdCguLG1hcHBpbmcgPSBhZXMoeCA9IGRlc2NyaXBjaW9uX2NhbXBhbmlhLA0KICAgICAgICAgICAgICAgICAgICAgICB5ID0gdmFsb3JlcywgZ3JvdXA9MSkpICsNCiAgZ2VvbV9saW5lKCkgKyBnZW9tX3BvaW50KCkrDQogIGZhY2V0X3dyYXAofmRlc2NyaXBjaW9uX3pvbmFfcmV0YWEpICsgIA0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICAiRmVydGlsaXphY2nDs24gY29uIFVyZWEgKGtnL2hhKSBlbiBUcmlnbyIpKw0KICBsYWJzKHg9IkNhbXBhw7FhIiwgY29sb3I9Ik5pdmVsIHRlY25vbMOzZ2ljbyIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSINCiAgICAgICAgKQ0KYGBgDQoNCiMjIyBQcmVjaW9zDQoNCmh0dHBzOi8vZW1vcmllYmVjay5naXRodWIuaW8vUi10dXRvcmlhbHMvcHVycnIvIw0KDQpgYGB7cn0NCnVuaXF1ZShwbGFudGVvcyR2YXJpYWJsZXMpICU+JSB3cml0ZS54bHN4KCJkYXRhc2V0cy9pbnN1bW9zX3BsYW50ZW9zLnhsc3giKQ0KYGBgDQoNCg0KDQo=